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