xref: /third_party/elfutils/src/findtextrel.c (revision da0c48c4)
1da0c48c4Sopenharmony_ci/* Locate source files or functions which caused text relocations.
2da0c48c4Sopenharmony_ci   Copyright (C) 2005-2010, 2012, 2014, 2018 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
5da0c48c4Sopenharmony_ci
6da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
7da0c48c4Sopenharmony_ci   it under the terms of the GNU General Public License as published by
8da0c48c4Sopenharmony_ci   the Free Software Foundation; either version 3 of the License, or
9da0c48c4Sopenharmony_ci   (at your option) any later version.
10da0c48c4Sopenharmony_ci
11da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
12da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
13da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14da0c48c4Sopenharmony_ci   GNU General Public License for more details.
15da0c48c4Sopenharmony_ci
16da0c48c4Sopenharmony_ci   You should have received a copy of the GNU General Public License
17da0c48c4Sopenharmony_ci   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18da0c48c4Sopenharmony_ci
19da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
20da0c48c4Sopenharmony_ci# include <config.h>
21da0c48c4Sopenharmony_ci#endif
22da0c48c4Sopenharmony_ci
23da0c48c4Sopenharmony_ci#include <argp.h>
24da0c48c4Sopenharmony_ci#include <assert.h>
25da0c48c4Sopenharmony_ci#include <errno.h>
26da0c48c4Sopenharmony_ci#include <fcntl.h>
27da0c48c4Sopenharmony_ci#include <gelf.h>
28da0c48c4Sopenharmony_ci#include <libdw.h>
29da0c48c4Sopenharmony_ci#include <locale.h>
30da0c48c4Sopenharmony_ci#include <search.h>
31da0c48c4Sopenharmony_ci#include <stdbool.h>
32da0c48c4Sopenharmony_ci#include <stdio.h>
33da0c48c4Sopenharmony_ci#include <stdlib.h>
34da0c48c4Sopenharmony_ci#include <string.h>
35da0c48c4Sopenharmony_ci#include <unistd.h>
36da0c48c4Sopenharmony_ci
37da0c48c4Sopenharmony_ci#include <printversion.h>
38da0c48c4Sopenharmony_ci#include "libeu.h"
39da0c48c4Sopenharmony_ci#include "system.h"
40da0c48c4Sopenharmony_ci
41da0c48c4Sopenharmony_cistruct segments
42da0c48c4Sopenharmony_ci{
43da0c48c4Sopenharmony_ci  GElf_Addr from;
44da0c48c4Sopenharmony_ci  GElf_Addr to;
45da0c48c4Sopenharmony_ci};
46da0c48c4Sopenharmony_ci
47da0c48c4Sopenharmony_ci
48da0c48c4Sopenharmony_ci/* Name and version of program.  */
49da0c48c4Sopenharmony_ciARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
50da0c48c4Sopenharmony_ci
51da0c48c4Sopenharmony_ci/* Bug report address.  */
52da0c48c4Sopenharmony_ciARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
53da0c48c4Sopenharmony_ci
54da0c48c4Sopenharmony_ci/* Values for the parameters which have no short form.  */
55da0c48c4Sopenharmony_ci#define OPT_DEBUGINFO 0x100
56da0c48c4Sopenharmony_ci
57da0c48c4Sopenharmony_ci/* Definitions of arguments for argp functions.  */
58da0c48c4Sopenharmony_cistatic const struct argp_option options[] =
59da0c48c4Sopenharmony_ci{
60da0c48c4Sopenharmony_ci  { NULL, 0, NULL, 0, N_("Input Selection:"), 0 },
61da0c48c4Sopenharmony_ci  { "root", 'r', "PATH", 0, N_("Prepend PATH to all file names"), 0 },
62da0c48c4Sopenharmony_ci  { "debuginfo", OPT_DEBUGINFO, "PATH", 0,
63da0c48c4Sopenharmony_ci    N_("Use PATH as root of debuginfo hierarchy"), 0 },
64da0c48c4Sopenharmony_ci
65da0c48c4Sopenharmony_ci  { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
66da0c48c4Sopenharmony_ci  { NULL, 0, NULL, 0, NULL, 0 }
67da0c48c4Sopenharmony_ci};
68da0c48c4Sopenharmony_ci
69da0c48c4Sopenharmony_ci/* Short description of program.  */
70da0c48c4Sopenharmony_cistatic const char doc[] = N_("\
71da0c48c4Sopenharmony_ciLocate source of text relocations in FILEs (a.out by default).");
72da0c48c4Sopenharmony_ci
73da0c48c4Sopenharmony_ci/* Strings for arguments in help texts.  */
74da0c48c4Sopenharmony_cistatic const char args_doc[] = N_("[FILE...]");
75da0c48c4Sopenharmony_ci
76da0c48c4Sopenharmony_ci/* Prototype for option handler.  */
77da0c48c4Sopenharmony_cistatic error_t parse_opt (int key, char *arg, struct argp_state *state);
78da0c48c4Sopenharmony_ci
79da0c48c4Sopenharmony_ci/* Data structure to communicate with argp functions.  */
80da0c48c4Sopenharmony_cistatic struct argp argp =
81da0c48c4Sopenharmony_ci{
82da0c48c4Sopenharmony_ci  options, parse_opt, args_doc, doc, NULL, NULL, NULL
83da0c48c4Sopenharmony_ci};
84da0c48c4Sopenharmony_ci
85da0c48c4Sopenharmony_ci
86da0c48c4Sopenharmony_ci/* Print symbols in file named FNAME.  */
87da0c48c4Sopenharmony_cistatic int process_file (const char *fname, bool more_than_one);
88da0c48c4Sopenharmony_ci
89da0c48c4Sopenharmony_ci/* Check for text relocations in the given file.  The segment
90da0c48c4Sopenharmony_ci   information is known.  */
91da0c48c4Sopenharmony_cistatic void check_rel (size_t nsegments, struct segments segments[nsegments],
92da0c48c4Sopenharmony_ci		       GElf_Addr addr, Elf *elf, Elf_Scn *symscn, Dwarf *dw,
93da0c48c4Sopenharmony_ci		       const char *fname, bool more_than_one,
94da0c48c4Sopenharmony_ci		       void **knownsrcs);
95da0c48c4Sopenharmony_ci
96da0c48c4Sopenharmony_ci
97da0c48c4Sopenharmony_ci
98da0c48c4Sopenharmony_ci/* User-provided root directory.  */
99da0c48c4Sopenharmony_cistatic const char *rootdir = "/";
100da0c48c4Sopenharmony_ci
101da0c48c4Sopenharmony_ci/* Root of debuginfo directory hierarchy.  */
102da0c48c4Sopenharmony_cistatic const char *debuginfo_root;
103da0c48c4Sopenharmony_ci
104da0c48c4Sopenharmony_ci
105da0c48c4Sopenharmony_ciint
106da0c48c4Sopenharmony_cimain (int argc, char *argv[])
107da0c48c4Sopenharmony_ci{
108da0c48c4Sopenharmony_ci  int remaining;
109da0c48c4Sopenharmony_ci  int result = 0;
110da0c48c4Sopenharmony_ci
111da0c48c4Sopenharmony_ci  /* Set locale.  */
112da0c48c4Sopenharmony_ci  (void) setlocale (LC_ALL, "");
113da0c48c4Sopenharmony_ci
114da0c48c4Sopenharmony_ci  /* Make sure the message catalog can be found.  */
115da0c48c4Sopenharmony_ci  (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
116da0c48c4Sopenharmony_ci
117da0c48c4Sopenharmony_ci  /* Initialize the message catalog.  */
118da0c48c4Sopenharmony_ci  (void) textdomain (PACKAGE_TARNAME);
119da0c48c4Sopenharmony_ci
120da0c48c4Sopenharmony_ci  /* Parse and process arguments.  */
121da0c48c4Sopenharmony_ci  (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
122da0c48c4Sopenharmony_ci
123da0c48c4Sopenharmony_ci  /* Tell the library which version we are expecting.  */
124da0c48c4Sopenharmony_ci  elf_version (EV_CURRENT);
125da0c48c4Sopenharmony_ci
126da0c48c4Sopenharmony_ci  /* If the user has not specified the root directory for the
127da0c48c4Sopenharmony_ci     debuginfo hierarchy, we have to determine it ourselves.  */
128da0c48c4Sopenharmony_ci  if (debuginfo_root == NULL)
129da0c48c4Sopenharmony_ci    {
130da0c48c4Sopenharmony_ci      // XXX The runtime should provide this information.
131da0c48c4Sopenharmony_ci#if defined __ia64__ || defined __alpha__
132da0c48c4Sopenharmony_ci      debuginfo_root = "/usr/lib/debug";
133da0c48c4Sopenharmony_ci#else
134da0c48c4Sopenharmony_ci      debuginfo_root = (sizeof (long int) == 4
135da0c48c4Sopenharmony_ci			? "/usr/lib/debug" : "/usr/lib64/debug");
136da0c48c4Sopenharmony_ci#endif
137da0c48c4Sopenharmony_ci    }
138da0c48c4Sopenharmony_ci
139da0c48c4Sopenharmony_ci  if (remaining == argc)
140da0c48c4Sopenharmony_ci    result = process_file ("a.out", false);
141da0c48c4Sopenharmony_ci  else
142da0c48c4Sopenharmony_ci    {
143da0c48c4Sopenharmony_ci      /* Process all the remaining files.  */
144da0c48c4Sopenharmony_ci      const bool more_than_one = remaining + 1 < argc;
145da0c48c4Sopenharmony_ci
146da0c48c4Sopenharmony_ci      do
147da0c48c4Sopenharmony_ci	result |= process_file (argv[remaining], more_than_one);
148da0c48c4Sopenharmony_ci      while (++remaining < argc);
149da0c48c4Sopenharmony_ci    }
150da0c48c4Sopenharmony_ci
151da0c48c4Sopenharmony_ci  return result;
152da0c48c4Sopenharmony_ci}
153da0c48c4Sopenharmony_ci
154da0c48c4Sopenharmony_ci
155da0c48c4Sopenharmony_ci/* Handle program arguments.  */
156da0c48c4Sopenharmony_cistatic error_t
157da0c48c4Sopenharmony_ciparse_opt (int key, char *arg,
158da0c48c4Sopenharmony_ci	   struct argp_state *state __attribute__ ((unused)))
159da0c48c4Sopenharmony_ci{
160da0c48c4Sopenharmony_ci  switch (key)
161da0c48c4Sopenharmony_ci    {
162da0c48c4Sopenharmony_ci    case 'r':
163da0c48c4Sopenharmony_ci      rootdir = arg;
164da0c48c4Sopenharmony_ci      break;
165da0c48c4Sopenharmony_ci
166da0c48c4Sopenharmony_ci    case OPT_DEBUGINFO:
167da0c48c4Sopenharmony_ci      debuginfo_root = arg;
168da0c48c4Sopenharmony_ci      break;
169da0c48c4Sopenharmony_ci
170da0c48c4Sopenharmony_ci    default:
171da0c48c4Sopenharmony_ci      return ARGP_ERR_UNKNOWN;
172da0c48c4Sopenharmony_ci    }
173da0c48c4Sopenharmony_ci  return 0;
174da0c48c4Sopenharmony_ci}
175da0c48c4Sopenharmony_ci
176da0c48c4Sopenharmony_ci
177da0c48c4Sopenharmony_cistatic void
178da0c48c4Sopenharmony_cinoop (void *arg __attribute__ ((unused)))
179da0c48c4Sopenharmony_ci{
180da0c48c4Sopenharmony_ci}
181da0c48c4Sopenharmony_ci
182da0c48c4Sopenharmony_ci
183da0c48c4Sopenharmony_cistatic int
184da0c48c4Sopenharmony_ciopen_rootdir_file (const char *fname)
185da0c48c4Sopenharmony_ci{
186da0c48c4Sopenharmony_ci  char *new_fname = NULL;
187da0c48c4Sopenharmony_ci  const char *real_fname = fname;
188da0c48c4Sopenharmony_ci
189da0c48c4Sopenharmony_ci  if (fname[0] == '/' && (rootdir[0] != '/' || rootdir[1] != '\0'))
190da0c48c4Sopenharmony_ci    real_fname = new_fname = xasprintf ("%s/%s", rootdir, fname);
191da0c48c4Sopenharmony_ci
192da0c48c4Sopenharmony_ci  int fd = open (real_fname, O_RDONLY);
193da0c48c4Sopenharmony_ci  if (fd == -1)
194da0c48c4Sopenharmony_ci    error (0, errno, _("cannot open '%s'"), fname);
195da0c48c4Sopenharmony_ci
196da0c48c4Sopenharmony_ci  free (new_fname);
197da0c48c4Sopenharmony_ci  return fd;
198da0c48c4Sopenharmony_ci}
199da0c48c4Sopenharmony_ci
200da0c48c4Sopenharmony_ci
201da0c48c4Sopenharmony_cistatic int
202da0c48c4Sopenharmony_ciprocess_file (const char *fname, bool more_than_one)
203da0c48c4Sopenharmony_ci{
204da0c48c4Sopenharmony_ci  int result = 0;
205da0c48c4Sopenharmony_ci  void *knownsrcs = NULL;
206da0c48c4Sopenharmony_ci  int fd = open_rootdir_file (fname);
207da0c48c4Sopenharmony_ci  if (fd == -1)
208da0c48c4Sopenharmony_ci    return 1;
209da0c48c4Sopenharmony_ci
210da0c48c4Sopenharmony_ci  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
211da0c48c4Sopenharmony_ci  if (elf == NULL)
212da0c48c4Sopenharmony_ci    {
213da0c48c4Sopenharmony_ci      error (0, 0, _("cannot create ELF descriptor for '%s': %s"),
214da0c48c4Sopenharmony_ci	     fname, elf_errmsg (-1));
215da0c48c4Sopenharmony_ci      goto err_close;
216da0c48c4Sopenharmony_ci    }
217da0c48c4Sopenharmony_ci
218da0c48c4Sopenharmony_ci  /* Make sure the file is a DSO.  */
219da0c48c4Sopenharmony_ci  GElf_Ehdr ehdr_mem;
220da0c48c4Sopenharmony_ci  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
221da0c48c4Sopenharmony_ci  if (ehdr == NULL)
222da0c48c4Sopenharmony_ci    {
223da0c48c4Sopenharmony_ci      error (0, 0, _("cannot get ELF header '%s': %s"),
224da0c48c4Sopenharmony_ci	     fname, elf_errmsg (-1));
225da0c48c4Sopenharmony_ci    err_elf_close:
226da0c48c4Sopenharmony_ci      elf_end (elf);
227da0c48c4Sopenharmony_ci    err_close:
228da0c48c4Sopenharmony_ci      close (fd);
229da0c48c4Sopenharmony_ci      return 1;
230da0c48c4Sopenharmony_ci    }
231da0c48c4Sopenharmony_ci
232da0c48c4Sopenharmony_ci  if (ehdr->e_type != ET_DYN)
233da0c48c4Sopenharmony_ci    {
234da0c48c4Sopenharmony_ci      error (0, 0, _("'%s' is not a DSO or PIE"), fname);
235da0c48c4Sopenharmony_ci      goto err_elf_close;
236da0c48c4Sopenharmony_ci    }
237da0c48c4Sopenharmony_ci
238da0c48c4Sopenharmony_ci  /* Determine whether the DSO has text relocations at all and locate
239da0c48c4Sopenharmony_ci     the symbol table.  */
240da0c48c4Sopenharmony_ci  Elf_Scn *symscn = NULL;
241da0c48c4Sopenharmony_ci  Elf_Scn *scn = NULL;
242da0c48c4Sopenharmony_ci  bool seen_dynamic = false;
243da0c48c4Sopenharmony_ci  bool have_textrel = false;
244da0c48c4Sopenharmony_ci  while ((scn = elf_nextscn (elf, scn)) != NULL
245da0c48c4Sopenharmony_ci	 && (!seen_dynamic || symscn == NULL))
246da0c48c4Sopenharmony_ci    {
247da0c48c4Sopenharmony_ci      /* Handle the section if it is a symbol table.  */
248da0c48c4Sopenharmony_ci      GElf_Shdr shdr_mem;
249da0c48c4Sopenharmony_ci      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
250da0c48c4Sopenharmony_ci
251da0c48c4Sopenharmony_ci      if (shdr == NULL)
252da0c48c4Sopenharmony_ci	{
253da0c48c4Sopenharmony_ci	  error (0, 0,
254da0c48c4Sopenharmony_ci		 _("getting get section header of section %zu: %s"),
255da0c48c4Sopenharmony_ci		 elf_ndxscn (scn), elf_errmsg (-1));
256da0c48c4Sopenharmony_ci	  goto err_elf_close;
257da0c48c4Sopenharmony_ci	}
258da0c48c4Sopenharmony_ci
259da0c48c4Sopenharmony_ci      switch (shdr->sh_type)
260da0c48c4Sopenharmony_ci	{
261da0c48c4Sopenharmony_ci	case SHT_DYNAMIC:
262da0c48c4Sopenharmony_ci	  if (!seen_dynamic)
263da0c48c4Sopenharmony_ci	    {
264da0c48c4Sopenharmony_ci	      seen_dynamic = true;
265da0c48c4Sopenharmony_ci
266da0c48c4Sopenharmony_ci	      Elf_Data *data = elf_getdata (scn, NULL);
267da0c48c4Sopenharmony_ci	      size_t entries = (shdr->sh_entsize == 0
268da0c48c4Sopenharmony_ci				? 0 : shdr->sh_size / shdr->sh_entsize);
269da0c48c4Sopenharmony_ci
270da0c48c4Sopenharmony_ci	      for (size_t cnt = 0; cnt < entries; ++cnt)
271da0c48c4Sopenharmony_ci		{
272da0c48c4Sopenharmony_ci		  GElf_Dyn dynmem;
273da0c48c4Sopenharmony_ci		  GElf_Dyn *dyn;
274da0c48c4Sopenharmony_ci
275da0c48c4Sopenharmony_ci		  dyn = gelf_getdyn (data, cnt, &dynmem);
276da0c48c4Sopenharmony_ci		  if (dyn == NULL)
277da0c48c4Sopenharmony_ci		    {
278da0c48c4Sopenharmony_ci		      error (0, 0, _("cannot read dynamic section: %s"),
279da0c48c4Sopenharmony_ci			     elf_errmsg (-1));
280da0c48c4Sopenharmony_ci		      goto err_elf_close;
281da0c48c4Sopenharmony_ci		    }
282da0c48c4Sopenharmony_ci
283da0c48c4Sopenharmony_ci		  if (dyn->d_tag == DT_TEXTREL
284da0c48c4Sopenharmony_ci		      || (dyn->d_tag == DT_FLAGS
285da0c48c4Sopenharmony_ci			  && (dyn->d_un.d_val & DF_TEXTREL) != 0))
286da0c48c4Sopenharmony_ci		    have_textrel = true;
287da0c48c4Sopenharmony_ci		}
288da0c48c4Sopenharmony_ci	    }
289da0c48c4Sopenharmony_ci	  break;
290da0c48c4Sopenharmony_ci
291da0c48c4Sopenharmony_ci	case SHT_SYMTAB:
292da0c48c4Sopenharmony_ci	  symscn = scn;
293da0c48c4Sopenharmony_ci	  break;
294da0c48c4Sopenharmony_ci	}
295da0c48c4Sopenharmony_ci    }
296da0c48c4Sopenharmony_ci
297da0c48c4Sopenharmony_ci  if (!have_textrel)
298da0c48c4Sopenharmony_ci    {
299da0c48c4Sopenharmony_ci      error (0, 0, _("no text relocations reported in '%s'"), fname);
300da0c48c4Sopenharmony_ci      goto err_elf_close;
301da0c48c4Sopenharmony_ci    }
302da0c48c4Sopenharmony_ci
303da0c48c4Sopenharmony_ci  int fd2 = -1;
304da0c48c4Sopenharmony_ci  Elf *elf2 = NULL;
305da0c48c4Sopenharmony_ci  /* Get the address ranges for the loaded segments.  */
306da0c48c4Sopenharmony_ci  size_t nsegments_max = 10;
307da0c48c4Sopenharmony_ci  size_t nsegments = 0;
308da0c48c4Sopenharmony_ci  struct segments *segments = malloc (nsegments_max * sizeof (segments[0]));
309da0c48c4Sopenharmony_ci  if (segments == NULL)
310da0c48c4Sopenharmony_ci    error (1, errno, _("while reading ELF file"));
311da0c48c4Sopenharmony_ci
312da0c48c4Sopenharmony_ci  size_t phnum;
313da0c48c4Sopenharmony_ci  if (elf_getphdrnum (elf, &phnum) != 0)
314da0c48c4Sopenharmony_ci    error (1, 0, _("cannot get program header count: %s"),
315da0c48c4Sopenharmony_ci           elf_errmsg (-1));
316da0c48c4Sopenharmony_ci
317da0c48c4Sopenharmony_ci
318da0c48c4Sopenharmony_ci  for (size_t i = 0; i < phnum; ++i)
319da0c48c4Sopenharmony_ci    {
320da0c48c4Sopenharmony_ci      GElf_Phdr phdr_mem;
321da0c48c4Sopenharmony_ci      GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
322da0c48c4Sopenharmony_ci      if (phdr == NULL)
323da0c48c4Sopenharmony_ci	{
324da0c48c4Sopenharmony_ci	  error (0, 0,
325da0c48c4Sopenharmony_ci		 _("cannot get program header index at offset %zd: %s"),
326da0c48c4Sopenharmony_ci		 i, elf_errmsg (-1));
327da0c48c4Sopenharmony_ci	  result = 1;
328da0c48c4Sopenharmony_ci	  goto next;
329da0c48c4Sopenharmony_ci	}
330da0c48c4Sopenharmony_ci
331da0c48c4Sopenharmony_ci      if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_W) == 0)
332da0c48c4Sopenharmony_ci	{
333da0c48c4Sopenharmony_ci	  if (nsegments == nsegments_max)
334da0c48c4Sopenharmony_ci	    {
335da0c48c4Sopenharmony_ci	      nsegments_max *= 2;
336da0c48c4Sopenharmony_ci	      segments
337da0c48c4Sopenharmony_ci		= realloc (segments, nsegments_max * sizeof (segments[0]));
338da0c48c4Sopenharmony_ci	      if (segments == NULL)
339da0c48c4Sopenharmony_ci		{
340da0c48c4Sopenharmony_ci		  error (0, 0, _("\
341da0c48c4Sopenharmony_cicannot get program header index at offset %zd: %s"),
342da0c48c4Sopenharmony_ci			 i, elf_errmsg (-1));
343da0c48c4Sopenharmony_ci		  result = 1;
344da0c48c4Sopenharmony_ci		  goto next;
345da0c48c4Sopenharmony_ci		}
346da0c48c4Sopenharmony_ci	    }
347da0c48c4Sopenharmony_ci
348da0c48c4Sopenharmony_ci	  segments[nsegments].from = phdr->p_vaddr;
349da0c48c4Sopenharmony_ci	  segments[nsegments].to = phdr->p_vaddr + phdr->p_memsz;
350da0c48c4Sopenharmony_ci	  ++nsegments;
351da0c48c4Sopenharmony_ci	}
352da0c48c4Sopenharmony_ci    }
353da0c48c4Sopenharmony_ci
354da0c48c4Sopenharmony_ci  if (nsegments > 0)
355da0c48c4Sopenharmony_ci    {
356da0c48c4Sopenharmony_ci
357da0c48c4Sopenharmony_ci      Dwarf *dw = dwarf_begin_elf (elf, DWARF_C_READ, NULL);
358da0c48c4Sopenharmony_ci      /* Look for debuginfo files if the information is not the in
359da0c48c4Sopenharmony_ci	 opened file itself.  This makes only sense if the input file
360da0c48c4Sopenharmony_ci	 is specified with an absolute path.  */
361da0c48c4Sopenharmony_ci      if (dw == NULL && fname[0] == '/')
362da0c48c4Sopenharmony_ci	{
363da0c48c4Sopenharmony_ci	  char *difname =
364da0c48c4Sopenharmony_ci	    xasprintf("%s%s/%s.debug", rootdir, debuginfo_root, fname);
365da0c48c4Sopenharmony_ci	  fd2 = open (difname, O_RDONLY);
366da0c48c4Sopenharmony_ci	  free (difname);
367da0c48c4Sopenharmony_ci	  if (fd2 != -1
368da0c48c4Sopenharmony_ci	      && (elf2 = elf_begin (fd2, ELF_C_READ_MMAP, NULL)) != NULL)
369da0c48c4Sopenharmony_ci	    dw = dwarf_begin_elf (elf2, DWARF_C_READ, NULL);
370da0c48c4Sopenharmony_ci	}
371da0c48c4Sopenharmony_ci
372da0c48c4Sopenharmony_ci      /* Look at all relocations and determine which modify
373da0c48c4Sopenharmony_ci	 write-protected segments.  */
374da0c48c4Sopenharmony_ci      scn = NULL;
375da0c48c4Sopenharmony_ci      while ((scn = elf_nextscn (elf, scn)) != NULL)
376da0c48c4Sopenharmony_ci	{
377da0c48c4Sopenharmony_ci	  /* Handle the section if it is a symbol table.  */
378da0c48c4Sopenharmony_ci	  GElf_Shdr shdr_mem;
379da0c48c4Sopenharmony_ci	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
380da0c48c4Sopenharmony_ci
381da0c48c4Sopenharmony_ci	  if (shdr == NULL)
382da0c48c4Sopenharmony_ci	    {
383da0c48c4Sopenharmony_ci	      error (0, 0,
384da0c48c4Sopenharmony_ci		     _("cannot get section header of section %zu: %s"),
385da0c48c4Sopenharmony_ci		     elf_ndxscn (scn), elf_errmsg (-1));
386da0c48c4Sopenharmony_ci	      result = 1;
387da0c48c4Sopenharmony_ci	      goto next;
388da0c48c4Sopenharmony_ci	    }
389da0c48c4Sopenharmony_ci
390da0c48c4Sopenharmony_ci	  if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
391da0c48c4Sopenharmony_ci	      && symscn == NULL)
392da0c48c4Sopenharmony_ci	    {
393da0c48c4Sopenharmony_ci	      symscn = elf_getscn (elf, shdr->sh_link);
394da0c48c4Sopenharmony_ci	      if (symscn == NULL)
395da0c48c4Sopenharmony_ci		{
396da0c48c4Sopenharmony_ci		  error (0, 0, _("\
397da0c48c4Sopenharmony_cicannot get symbol table section %zu in '%s': %s"),
398da0c48c4Sopenharmony_ci			 (size_t) shdr->sh_link, fname, elf_errmsg (-1));
399da0c48c4Sopenharmony_ci		  result = 1;
400da0c48c4Sopenharmony_ci		  goto next;
401da0c48c4Sopenharmony_ci		}
402da0c48c4Sopenharmony_ci	    }
403da0c48c4Sopenharmony_ci
404da0c48c4Sopenharmony_ci	  if (shdr->sh_type == SHT_REL)
405da0c48c4Sopenharmony_ci	    {
406da0c48c4Sopenharmony_ci	      Elf_Data *data = elf_getdata (scn, NULL);
407da0c48c4Sopenharmony_ci	      size_t entries = (shdr->sh_entsize == 0
408da0c48c4Sopenharmony_ci				? 0 : shdr->sh_size / shdr->sh_entsize);
409da0c48c4Sopenharmony_ci
410da0c48c4Sopenharmony_ci	      for (int cnt = 0;
411da0c48c4Sopenharmony_ci		   (size_t) cnt < entries; ++cnt)
412da0c48c4Sopenharmony_ci		{
413da0c48c4Sopenharmony_ci		  GElf_Rel rel_mem;
414da0c48c4Sopenharmony_ci		  GElf_Rel *rel = gelf_getrel (data, cnt, &rel_mem);
415da0c48c4Sopenharmony_ci		  if (rel == NULL)
416da0c48c4Sopenharmony_ci		    {
417da0c48c4Sopenharmony_ci		      error (0, 0, _("\
418da0c48c4Sopenharmony_cicannot get relocation at index %d in section %zu in '%s': %s"),
419da0c48c4Sopenharmony_ci			     cnt, elf_ndxscn (scn), fname, elf_errmsg (-1));
420da0c48c4Sopenharmony_ci		      result = 1;
421da0c48c4Sopenharmony_ci		      goto next;
422da0c48c4Sopenharmony_ci		    }
423da0c48c4Sopenharmony_ci
424da0c48c4Sopenharmony_ci		  check_rel (nsegments, segments, rel->r_offset, elf,
425da0c48c4Sopenharmony_ci			     symscn, dw, fname, more_than_one, &knownsrcs);
426da0c48c4Sopenharmony_ci		}
427da0c48c4Sopenharmony_ci	    }
428da0c48c4Sopenharmony_ci	  else if (shdr->sh_type == SHT_RELA)
429da0c48c4Sopenharmony_ci	    {
430da0c48c4Sopenharmony_ci	      Elf_Data *data = elf_getdata (scn, NULL);
431da0c48c4Sopenharmony_ci	      size_t entries = (shdr->sh_entsize == 0
432da0c48c4Sopenharmony_ci				? 0 : shdr->sh_size / shdr->sh_entsize);
433da0c48c4Sopenharmony_ci
434da0c48c4Sopenharmony_ci	      for (int cnt = 0; (size_t) cnt < entries; ++cnt)
435da0c48c4Sopenharmony_ci		{
436da0c48c4Sopenharmony_ci		  GElf_Rela rela_mem;
437da0c48c4Sopenharmony_ci		  GElf_Rela *rela = gelf_getrela (data, cnt, &rela_mem);
438da0c48c4Sopenharmony_ci		  if (rela == NULL)
439da0c48c4Sopenharmony_ci		    {
440da0c48c4Sopenharmony_ci		      error (0, 0, _("\
441da0c48c4Sopenharmony_cicannot get relocation at index %d in section %zu in '%s': %s"),
442da0c48c4Sopenharmony_ci			     cnt, elf_ndxscn (scn), fname, elf_errmsg (-1));
443da0c48c4Sopenharmony_ci		      result = 1;
444da0c48c4Sopenharmony_ci		      goto next;
445da0c48c4Sopenharmony_ci		    }
446da0c48c4Sopenharmony_ci
447da0c48c4Sopenharmony_ci		  check_rel (nsegments, segments, rela->r_offset, elf,
448da0c48c4Sopenharmony_ci			     symscn, dw, fname, more_than_one, &knownsrcs);
449da0c48c4Sopenharmony_ci		}
450da0c48c4Sopenharmony_ci	    }
451da0c48c4Sopenharmony_ci	}
452da0c48c4Sopenharmony_ci
453da0c48c4Sopenharmony_ci      dwarf_end (dw);
454da0c48c4Sopenharmony_ci    }
455da0c48c4Sopenharmony_ci
456da0c48c4Sopenharmony_ci next:
457da0c48c4Sopenharmony_ci  elf_end (elf);
458da0c48c4Sopenharmony_ci  elf_end (elf2);
459da0c48c4Sopenharmony_ci  close (fd);
460da0c48c4Sopenharmony_ci  if (fd2 != -1)
461da0c48c4Sopenharmony_ci    close (fd2);
462da0c48c4Sopenharmony_ci
463da0c48c4Sopenharmony_ci  free (segments);
464da0c48c4Sopenharmony_ci  tdestroy (knownsrcs, noop);
465da0c48c4Sopenharmony_ci
466da0c48c4Sopenharmony_ci  return result;
467da0c48c4Sopenharmony_ci}
468da0c48c4Sopenharmony_ci
469da0c48c4Sopenharmony_ci
470da0c48c4Sopenharmony_cistatic int
471da0c48c4Sopenharmony_ciptrcompare (const void *p1, const void *p2)
472da0c48c4Sopenharmony_ci{
473da0c48c4Sopenharmony_ci  if ((uintptr_t) p1 < (uintptr_t) p2)
474da0c48c4Sopenharmony_ci    return -1;
475da0c48c4Sopenharmony_ci  if ((uintptr_t) p1 > (uintptr_t) p2)
476da0c48c4Sopenharmony_ci    return 1;
477da0c48c4Sopenharmony_ci  return 0;
478da0c48c4Sopenharmony_ci}
479da0c48c4Sopenharmony_ci
480da0c48c4Sopenharmony_ci
481da0c48c4Sopenharmony_cistatic void
482da0c48c4Sopenharmony_cicheck_rel (size_t nsegments, struct segments segments[nsegments],
483da0c48c4Sopenharmony_ci	   GElf_Addr addr, Elf *elf, Elf_Scn *symscn, Dwarf *dw,
484da0c48c4Sopenharmony_ci	   const char *fname, bool more_than_one, void **knownsrcs)
485da0c48c4Sopenharmony_ci{
486da0c48c4Sopenharmony_ci  for (size_t cnt = 0; cnt < nsegments; ++cnt)
487da0c48c4Sopenharmony_ci    if (segments[cnt].from <= addr && segments[cnt].to > addr)
488da0c48c4Sopenharmony_ci      {
489da0c48c4Sopenharmony_ci	Dwarf_Die die_mem;
490da0c48c4Sopenharmony_ci	Dwarf_Die *die;
491da0c48c4Sopenharmony_ci	Dwarf_Line *line;
492da0c48c4Sopenharmony_ci	const char *src;
493da0c48c4Sopenharmony_ci
494da0c48c4Sopenharmony_ci	if (more_than_one)
495da0c48c4Sopenharmony_ci	  printf ("%s: ", fname);
496da0c48c4Sopenharmony_ci
497da0c48c4Sopenharmony_ci	if ((die = dwarf_addrdie (dw, addr, &die_mem)) != NULL
498da0c48c4Sopenharmony_ci	    && (line = dwarf_getsrc_die (die, addr)) != NULL
499da0c48c4Sopenharmony_ci	    && (src = dwarf_linesrc (line, NULL, NULL)) != NULL)
500da0c48c4Sopenharmony_ci	  {
501da0c48c4Sopenharmony_ci	    /* There can be more than one relocation against one file.
502da0c48c4Sopenharmony_ci	       Try to avoid multiple messages.  And yes, the code uses
503da0c48c4Sopenharmony_ci	       pointer comparison.  */
504da0c48c4Sopenharmony_ci	    if (tfind (src, knownsrcs, ptrcompare) == NULL)
505da0c48c4Sopenharmony_ci	      {
506da0c48c4Sopenharmony_ci		printf (_("%s not compiled with -fpic/-fPIC\n"), src);
507da0c48c4Sopenharmony_ci		tsearch (src, knownsrcs, ptrcompare);
508da0c48c4Sopenharmony_ci	      }
509da0c48c4Sopenharmony_ci	    return;
510da0c48c4Sopenharmony_ci	  }
511da0c48c4Sopenharmony_ci	else
512da0c48c4Sopenharmony_ci	  {
513da0c48c4Sopenharmony_ci	    /* At least look at the symbol table to see which function
514da0c48c4Sopenharmony_ci	       the modified address is in.  */
515da0c48c4Sopenharmony_ci	    Elf_Data *symdata = elf_getdata (symscn, NULL);
516da0c48c4Sopenharmony_ci	    GElf_Shdr shdr_mem;
517da0c48c4Sopenharmony_ci	    GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
518da0c48c4Sopenharmony_ci	    if (shdr != NULL)
519da0c48c4Sopenharmony_ci	      {
520da0c48c4Sopenharmony_ci		GElf_Addr lowaddr = 0;
521da0c48c4Sopenharmony_ci		int lowidx = -1;
522da0c48c4Sopenharmony_ci		GElf_Addr highaddr = ~0ul;
523da0c48c4Sopenharmony_ci		int highidx = -1;
524da0c48c4Sopenharmony_ci		GElf_Sym sym_mem;
525da0c48c4Sopenharmony_ci		GElf_Sym *sym;
526da0c48c4Sopenharmony_ci		size_t entries = (shdr->sh_entsize == 0
527da0c48c4Sopenharmony_ci				  ? 0 : shdr->sh_size / shdr->sh_entsize);
528da0c48c4Sopenharmony_ci
529da0c48c4Sopenharmony_ci		for (int i = 0; (size_t) i < entries; ++i)
530da0c48c4Sopenharmony_ci		  {
531da0c48c4Sopenharmony_ci		    sym = gelf_getsym (symdata, i, &sym_mem);
532da0c48c4Sopenharmony_ci		    if (sym == NULL)
533da0c48c4Sopenharmony_ci		      continue;
534da0c48c4Sopenharmony_ci
535da0c48c4Sopenharmony_ci		    if (sym->st_value < addr && sym->st_value > lowaddr)
536da0c48c4Sopenharmony_ci		      {
537da0c48c4Sopenharmony_ci			lowaddr = sym->st_value;
538da0c48c4Sopenharmony_ci			lowidx = i;
539da0c48c4Sopenharmony_ci		      }
540da0c48c4Sopenharmony_ci		    if (sym->st_value > addr && sym->st_value < highaddr)
541da0c48c4Sopenharmony_ci		      {
542da0c48c4Sopenharmony_ci			highaddr = sym->st_value;
543da0c48c4Sopenharmony_ci			highidx = i;
544da0c48c4Sopenharmony_ci		      }
545da0c48c4Sopenharmony_ci		  }
546da0c48c4Sopenharmony_ci
547da0c48c4Sopenharmony_ci		if (lowidx != -1)
548da0c48c4Sopenharmony_ci		  {
549da0c48c4Sopenharmony_ci		    sym = gelf_getsym (symdata, lowidx, &sym_mem);
550da0c48c4Sopenharmony_ci		    assert (sym != NULL);
551da0c48c4Sopenharmony_ci
552da0c48c4Sopenharmony_ci		    const char *lowstr = elf_strptr (elf, shdr->sh_link,
553da0c48c4Sopenharmony_ci						     sym->st_name);
554da0c48c4Sopenharmony_ci
555da0c48c4Sopenharmony_ci		    if (sym->st_value + sym->st_size > addr)
556da0c48c4Sopenharmony_ci		      {
557da0c48c4Sopenharmony_ci			/* It is this function.  */
558da0c48c4Sopenharmony_ci			if (tfind (lowstr, knownsrcs, ptrcompare) == NULL)
559da0c48c4Sopenharmony_ci			  {
560da0c48c4Sopenharmony_ci			    printf (_("\
561da0c48c4Sopenharmony_cithe file containing the function '%s' is not compiled with -fpic/-fPIC\n"),
562da0c48c4Sopenharmony_ci				    lowstr);
563da0c48c4Sopenharmony_ci			    tsearch (lowstr, knownsrcs, ptrcompare);
564da0c48c4Sopenharmony_ci			  }
565da0c48c4Sopenharmony_ci		      }
566da0c48c4Sopenharmony_ci		    else if (highidx == -1)
567da0c48c4Sopenharmony_ci		      printf (_("\
568da0c48c4Sopenharmony_cithe file containing the function '%s' might not be compiled with -fpic/-fPIC\n"),
569da0c48c4Sopenharmony_ci			      lowstr);
570da0c48c4Sopenharmony_ci		    else
571da0c48c4Sopenharmony_ci		      {
572da0c48c4Sopenharmony_ci			sym = gelf_getsym (symdata, highidx, &sym_mem);
573da0c48c4Sopenharmony_ci			assert (sym != NULL);
574da0c48c4Sopenharmony_ci
575da0c48c4Sopenharmony_ci			printf (_("\
576da0c48c4Sopenharmony_cieither the file containing the function '%s' or the file containing the function '%s' is not compiled with -fpic/-fPIC\n"),
577da0c48c4Sopenharmony_ci				lowstr, elf_strptr (elf, shdr->sh_link,
578da0c48c4Sopenharmony_ci						    sym->st_name));
579da0c48c4Sopenharmony_ci		      }
580da0c48c4Sopenharmony_ci		    return;
581da0c48c4Sopenharmony_ci		  }
582da0c48c4Sopenharmony_ci		else if (highidx != -1)
583da0c48c4Sopenharmony_ci		  {
584da0c48c4Sopenharmony_ci		    sym = gelf_getsym (symdata, highidx, &sym_mem);
585da0c48c4Sopenharmony_ci		    assert (sym != NULL);
586da0c48c4Sopenharmony_ci
587da0c48c4Sopenharmony_ci		    printf (_("\
588da0c48c4Sopenharmony_cithe file containing the function '%s' might not be compiled with -fpic/-fPIC\n"),
589da0c48c4Sopenharmony_ci			    elf_strptr (elf, shdr->sh_link, sym->st_name));
590da0c48c4Sopenharmony_ci		    return;
591da0c48c4Sopenharmony_ci		  }
592da0c48c4Sopenharmony_ci	      }
593da0c48c4Sopenharmony_ci	  }
594da0c48c4Sopenharmony_ci
595da0c48c4Sopenharmony_ci	printf (_("\
596da0c48c4Sopenharmony_cia relocation modifies memory at offset %llu in a write-protected segment\n"),
597da0c48c4Sopenharmony_ci		(unsigned long long int) addr);
598da0c48c4Sopenharmony_ci	break;
599da0c48c4Sopenharmony_ci      }
600da0c48c4Sopenharmony_ci}
601da0c48c4Sopenharmony_ci
602da0c48c4Sopenharmony_ci
603da0c48c4Sopenharmony_ci#include "debugpred.h"
604