xref: /aosp_15_r20/external/elfutils/src/findtextrel.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
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