* Makerules: Define build-module-asneeded.
[platform/upstream/glibc.git] / elf / check-localplt.c
1 /* Show local PLT use in DSOs.
2    Copyright (C) 2006 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contribute by Ulrich Drepper <drepper@redhat.com>. 2006.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <byteswap.h>
22 #include <elf.h>
23 #include <endian.h>
24 #include <fcntl.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31
32 #ifdef BITS
33
34 # define AB(name) _AB (name, BITS)
35 # define _AB(name, bits) __AB (name, bits)
36 # define __AB(name, bits) name##bits
37 # define E(name) _E (name, BITS)
38 # define _E(name, bits) __E (name, bits)
39 # define __E(name, bits) Elf##bits##_##name
40 # define EE(name) _EE (name, BITS)
41 # define _EE(name, bits) __EE (name, bits)
42 # define __EE(name, bits) ELF##bits##_##name
43 # define SWAP(val) \
44   ({ __typeof (val) __res;                                                    \
45      if (((ehdr.e_ident[EI_DATA] == ELFDATA2MSB                               \
46            && BYTE_ORDER == LITTLE_ENDIAN)                                    \
47           || (ehdr.e_ident[EI_DATA] == ELFDATA2LSB                            \
48               && BYTE_ORDER == BIG_ENDIAN))                                   \
49          && sizeof (val) != 1)                                                \
50        {                                                                      \
51          if (sizeof (val) == 2)                                               \
52            __res = bswap_16 (val);                                            \
53          else if (sizeof (val) == 4)                                          \
54            __res = bswap_32 (val);                                            \
55          else                                                                 \
56            __res = bswap_64 (val);                                            \
57        }                                                                      \
58      else                                                                     \
59        __res = (val);                                                         \
60      __res; })
61
62
63 static int
64 AB(handle_file) (const char *fname, int fd)
65 {
66   E(Ehdr) ehdr;
67
68   if (pread (fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
69     {
70     read_error:
71       printf ("%s: read error: %m\n", fname);
72       return 1;
73     }
74
75   const size_t phnum = SWAP (ehdr.e_phnum);
76   const size_t phentsize = SWAP (ehdr.e_phentsize);
77
78   /* Read the program header.  */
79   E(Phdr) *phdr = alloca (phentsize * phnum);
80   if (pread (fd, phdr, phentsize * phnum, SWAP (ehdr.e_phoff))
81       != phentsize * phnum)
82     goto read_error;
83
84   /* Search for the PT_DYNAMIC entry.  */
85   size_t cnt;
86   E(Phdr) *dynphdr = NULL;
87   for (cnt = 0; cnt < phnum; ++cnt)
88     if (SWAP (phdr[cnt].p_type) == PT_DYNAMIC)
89       {
90         dynphdr = &phdr[cnt];
91         break;
92       }
93
94   if (dynphdr == NULL)
95     {
96       printf ("%s: no DYNAMIC segment found\n", fname);
97       return 1;
98     }
99
100   /* Read the dynamic segment.  */
101   size_t pmemsz = SWAP(dynphdr->p_memsz);
102   E(Dyn) *dyn = alloca (pmemsz);
103   if (pread64 (fd, dyn, pmemsz, SWAP(dynphdr->p_offset)) != pmemsz)
104     goto read_error;
105
106   /* Search for an DT_PLTREL, DT_JMPREL, DT_PLTRELSZ, DT_STRTAB,
107      DT_STRSZ, and DT_SYMTAB entries.  */
108   size_t pltrel_idx = SIZE_MAX;
109   size_t jmprel_idx = SIZE_MAX;
110   size_t pltrelsz_idx = SIZE_MAX;
111   size_t strtab_idx = SIZE_MAX;
112   size_t strsz_idx = SIZE_MAX;
113   size_t symtab_idx = SIZE_MAX;
114   for (cnt = 0; (cnt + 1) * sizeof (E(Dyn)) - 1 < pmemsz; ++cnt)
115     {
116       unsigned int tag = SWAP (dyn[cnt].d_tag);
117
118       if (tag == DT_NULL)
119         /* We reached the end.  */
120         break;
121
122       if (tag == DT_PLTREL)
123         pltrel_idx = cnt;
124       else if (tag == DT_JMPREL)
125         jmprel_idx = cnt;
126       else if (tag == DT_PLTRELSZ)
127         pltrelsz_idx = cnt;
128       else if (tag == DT_STRTAB)
129         strtab_idx = cnt;
130       else if (tag == DT_STRSZ)
131         strsz_idx = cnt;
132       else if (tag == DT_SYMTAB)
133         symtab_idx = cnt;
134     }
135
136   if (pltrel_idx == SIZE_MAX || jmprel_idx == SIZE_MAX
137       || pltrelsz_idx == SIZE_MAX || strtab_idx == SIZE_MAX
138       || strsz_idx == SIZE_MAX || symtab_idx == SIZE_MAX)
139     {
140       puts ("not all PLT information found");
141       return 1;
142     }
143
144   E(Xword) relsz = SWAP (dyn[pltrelsz_idx].d_un.d_val);
145
146   void *relmem = NULL;
147   char *strtab = NULL;
148   E(Xword) symtab_offset = 0;
149
150   /* Find the offset of DT_JMPREL and load the data.  */
151   for (cnt = 0; cnt < phnum; ++cnt)
152     if (SWAP (phdr[cnt].p_type) == PT_LOAD)
153       {
154         E(Addr) vaddr = SWAP (phdr[cnt].p_vaddr);
155         E(Xword) memsz = SWAP (phdr[cnt].p_memsz);
156
157         if (vaddr <= SWAP (dyn[jmprel_idx].d_un.d_val)
158             && vaddr + memsz >= SWAP (dyn[jmprel_idx].d_un.d_val) + relsz)
159           {
160             relmem = alloca (SWAP (dyn[pltrelsz_idx].d_un.d_val));
161             if (pread64 (fd, relmem, relsz,
162                          SWAP (phdr[cnt].p_offset)
163                          + SWAP (dyn[jmprel_idx].d_un.d_val) - vaddr)
164                 != relsz)
165               {
166                 puts ("cannot read JMPREL");
167                 return 1;
168               }
169           }
170
171         if (vaddr <= SWAP (dyn[symtab_idx].d_un.d_val)
172             && vaddr + memsz > SWAP (dyn[symtab_idx].d_un.d_val))
173           symtab_offset = (SWAP (phdr[cnt].p_offset)
174                            + SWAP (dyn[symtab_idx].d_un.d_val) - vaddr);
175
176         if (vaddr <= SWAP (dyn[strtab_idx].d_un.d_val)
177             && vaddr + memsz >= (SWAP (dyn[strtab_idx].d_un.d_val)
178                                  + SWAP(dyn[strsz_idx].d_un.d_val)))
179           {
180             strtab = alloca (SWAP(dyn[strsz_idx].d_un.d_val));
181             if (pread64 (fd, strtab, SWAP(dyn[strsz_idx].d_un.d_val),
182                          SWAP (phdr[cnt].p_offset)
183                          + SWAP (dyn[strtab_idx].d_un.d_val) - vaddr)
184                 != SWAP(dyn[strsz_idx].d_un.d_val))
185               {
186                 puts ("cannot read STRTAB");
187                 return 1;
188               }
189           }
190       }
191
192   if (relmem == NULL || strtab == NULL || symtab_offset == 0)
193     {
194       puts ("couldn't load PLT data");
195       return 1;
196     }
197
198   if (SWAP (dyn[pltrel_idx].d_un.d_val) == DT_RELA)
199     for (E(Rela) *rela = relmem; (char *) rela - (char *) relmem < relsz;
200          ++rela)
201       {
202         E(Sym) sym;
203
204         if (pread64 (fd, &sym, sizeof (sym),
205                      symtab_offset
206                      + EE(R_SYM) (SWAP (rela->r_info)) * sizeof (sym))
207             != sizeof (sym))
208           {
209             puts ("cannot read symbol");
210             return 1;
211           }
212
213         if (sym.st_value != 0)
214           /* This symbol is locally defined.  */
215           printf ("%s: %s\n", basename (fname), strtab + SWAP (sym.st_name));
216       }
217   else
218     for (E(Rel) *rel = relmem; (char *) rel - (char *) relmem < relsz; ++rel)
219       {
220         E(Sym) sym;
221
222         if (pread64 (fd, &sym, sizeof (sym),
223                      symtab_offset
224                      + EE(R_SYM) (SWAP (rel->r_info)) * sizeof (sym))
225             != sizeof (sym))
226           {
227             puts ("cannot read symbol");
228             return 1;
229           }
230
231         if (sym.st_value != 0)
232           /* This symbol is locally defined.  */
233           printf ("%s: %s\n", basename (fname), strtab + SWAP (sym.st_name));
234       }
235
236   return 0;
237 }
238
239 # undef BITS
240 #else
241
242 # define BITS 32
243 # include "check-localplt.c"
244
245 # define BITS 64
246 # include "check-localplt.c"
247
248
249 static int
250 handle_file (const char *fname)
251 {
252   int fd = open (fname, O_RDONLY);
253   if (fd == -1)
254     {
255       printf ("cannot open %s: %m\n", fname);
256       return 1;
257     }
258
259   /* Read was is supposed to be the ELF header.  Read the initial
260      bytes to determine whether this is a 32 or 64 bit file.  */
261   char ident[EI_NIDENT];
262   if (read (fd, ident, EI_NIDENT) != EI_NIDENT)
263     {
264       printf ("%s: read error: %m\n", fname);
265       close (fd);
266       return 1;
267     }
268
269   if (memcmp (&ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
270     {
271       printf ("%s: not an ELF file\n", fname);
272       close (fd);
273       return 1;
274     }
275
276   int result;
277   if (ident[EI_CLASS] == ELFCLASS64)
278     result = handle_file64 (fname, fd);
279   else
280     result = handle_file32 (fname, fd);
281
282   close (fd);
283
284   return result;
285 }
286
287
288 int
289 main (int argc, char *argv[])
290 {
291   int cnt;
292   int result = 0;
293
294   for (cnt = 1; cnt < argc; ++cnt)
295     result |= handle_file (argv[cnt]);
296
297   return result;
298 }
299 #endif