/[gentoo-projects]/pax-utils/scanelf.c
Gentoo

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.76 - (hide annotations) (download) (as text)
Wed Jun 8 04:24:19 2005 UTC (9 years, 2 months ago) by vapier
Branch: MAIN
Changes since 1.75: +152 -35 lines
File MIME type: text/x-csrc
add support by kev quinn for showing textrels

1 solar 1.1 /*
2 solar 1.63 * Copyright 2003-2005 Gentoo Foundation
3 solar 1.1 * Distributed under the terms of the GNU General Public License v2
4 vapier 1.76 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.75 2005/06/06 23:32:38 vapier Exp $
5 solar 1.1 *
6     ********************************************************************
7     * This program is free software; you can redistribute it and/or
8     * modify it under the terms of the GNU General Public License as
9     * published by the Free Software Foundation; either version 2 of the
10     * License, or (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful, but
13     * WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     * General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20     * MA 02111-1307, USA.
21     */
22    
23     #include <stdio.h>
24     #include <stdlib.h>
25     #include <sys/types.h>
26 vapier 1.60 #include <libgen.h>
27     #include <limits.h>
28 solar 1.28 #define __USE_GNU
29 solar 1.1 #include <string.h>
30 vapier 1.10 #include <errno.h>
31 solar 1.1 #include <unistd.h>
32     #include <sys/stat.h>
33     #include <dirent.h>
34     #include <getopt.h>
35 solar 1.20 #include <assert.h>
36 solar 1.1 #include "paxelf.h"
37    
38 vapier 1.76 static const char *rcsid = "$Id: scanelf.c,v 1.75 2005/06/06 23:32:38 vapier Exp $";
39 vapier 1.36 #define argv0 "scanelf"
40 vapier 1.10
41 vapier 1.70 #define IS_MODIFIER(c) (c == '%' || c == '#')
42    
43 vapier 1.10
44    
45     /* prototypes */
46     static void scanelf_file(const char *filename);
47     static void scanelf_dir(const char *path);
48     static void scanelf_ldpath();
49     static void scanelf_envpath();
50     static void usage(int status);
51     static void parseargs(int argc, char *argv[]);
52 vapier 1.60 static char *xstrdup(const char *s);
53 vapier 1.41 static void *xmalloc(size_t size);
54     static void xstrcat(char **dst, const char *src, size_t *curr_len);
55     static inline void xchrcat(char **dst, const char append, size_t *curr_len);
56 vapier 1.10
57     /* variables to control behavior */
58 vapier 1.48 static char *ldpaths[256];
59 vapier 1.10 static char scan_ldpath = 0;
60     static char scan_envpath = 0;
61 vapier 1.37 static char scan_symlink = 1;
62 vapier 1.10 static char dir_recurse = 0;
63 vapier 1.14 static char dir_crossmount = 1;
64 vapier 1.10 static char show_pax = 0;
65 solar 1.73 static char show_phdr = 0;
66 vapier 1.10 static char show_textrel = 0;
67     static char show_rpath = 0;
68 vapier 1.32 static char show_needed = 0;
69 vapier 1.38 static char show_interp = 0;
70 vapier 1.49 static char show_bind = 0;
71 vapier 1.76 static char show_textrels = 0;
72 solar 1.16 static char show_banner = 1;
73 vapier 1.10 static char be_quiet = 0;
74 vapier 1.14 static char be_verbose = 0;
75 vapier 1.70 static char be_wewy_wewy_quiet = 0;
76 vapier 1.39 static char *find_sym = NULL, *versioned_symname = NULL;
77 vapier 1.72 static char *find_lib = NULL;
78 vapier 1.39 static char *out_format = NULL;
79 vapier 1.66 static char *search_path = NULL;
80 vapier 1.10
81 solar 1.1
82 vapier 1.70
83 vapier 1.39 /* sub-funcs for scanelf_file() */
84 vapier 1.41 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
85 solar 1.6 {
86 vapier 1.41 static char *paxflags;
87 solar 1.61 static char ret[7];
88     unsigned long i, shown;
89    
90 vapier 1.41
91     if (!show_pax) return NULL;
92 vapier 1.10
93 solar 1.61 shown = 0;
94     memset(&ret, 0, sizeof(ret));
95    
96     if (elf->phdr) {
97     #define SHOW_PAX(B) \
98     if (elf->elf_class == ELFCLASS ## B) { \
99     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
100     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
101     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
102     if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
103     continue; \
104     if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
105     continue; \
106     memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
107     *found_pax = 1; \
108     ++shown; \
109     break; \
110     } \
111     }
112     SHOW_PAX(32)
113     SHOW_PAX(64)
114     }
115    
116     /* fall back to EI_PAX if no PT_PAX was found */
117     if (!*ret) {
118     paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
119     if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
120     *found_pax = 1;
121     return paxflags;
122     }
123     strncpy(ret, paxflags, sizeof(ret));
124     // ++shown;
125 vapier 1.14 }
126 vapier 1.41
127 solar 1.61 if (be_quiet && !shown)
128     return NULL;
129     return ret;
130    
131 vapier 1.39 }
132 solar 1.73 static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
133 vapier 1.39 {
134 vapier 1.71 static char ret[12];
135 vapier 1.41 char *found;
136 vapier 1.71 unsigned long i, off, shown, check_flags;
137     unsigned char multi_stack, multi_relro, multi_load;
138 vapier 1.41
139 solar 1.73 if (!show_phdr) return NULL;
140 vapier 1.41
141 vapier 1.71 memcpy(ret, "--- --- ---\0", 12);
142    
143 vapier 1.41 shown = 0;
144 vapier 1.71 multi_stack = multi_relro = multi_load = 0;
145 vapier 1.44
146     if (elf->phdr) {
147 solar 1.73 #define SHOW_PHDR(B) \
148 vapier 1.39 if (elf->elf_class == ELFCLASS ## B) { \
149     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
150     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
151 vapier 1.71 uint32_t flags; \
152 vapier 1.39 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
153 vapier 1.41 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
154 vapier 1.71 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
155 solar 1.73 found = found_phdr; \
156 vapier 1.41 off = 0; \
157 vapier 1.71 check_flags = PF_X; \
158 vapier 1.41 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
159 vapier 1.71 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
160 vapier 1.41 found = found_relro; \
161 solar 1.53 off = 4; \
162 vapier 1.71 check_flags = PF_X; \
163     } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
164     if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \
165     found = found_load; \
166     off = 8; \
167     check_flags = PF_W|PF_X; \
168 vapier 1.41 } else \
169     continue; \
170 vapier 1.71 flags = EGET(phdr[i].p_flags); \
171     if (be_quiet && ((flags & check_flags) != check_flags)) \
172 vapier 1.39 continue; \
173 vapier 1.71 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \
174 vapier 1.41 *found = 1; \
175     ++shown; \
176 vapier 1.39 } \
177     }
178 solar 1.73 SHOW_PHDR(32)
179     SHOW_PHDR(64)
180 vapier 1.44 }
181    
182 vapier 1.41 if (be_quiet && !shown)
183     return NULL;
184     else
185     return ret;
186 vapier 1.39 }
187 vapier 1.41 static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
188 vapier 1.39 {
189 solar 1.68 static char ret[] = "TEXTREL";
190 vapier 1.44 unsigned long i;
191 vapier 1.41
192     if (!show_textrel) return NULL;
193    
194 vapier 1.44 if (elf->phdr) {
195 vapier 1.39 #define SHOW_TEXTREL(B) \
196     if (elf->elf_class == ELFCLASS ## B) { \
197     Elf ## B ## _Dyn *dyn; \
198     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
199     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
200 vapier 1.44 Elf ## B ## _Off offset; \
201 vapier 1.39 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
202 vapier 1.59 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
203 vapier 1.44 offset = EGET(phdr[i].p_offset); \
204     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
205     dyn = DYN ## B (elf->data + offset); \
206 vapier 1.39 while (EGET(dyn->d_tag) != DT_NULL) { \
207     if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
208     *found_textrel = 1; \
209     /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
210 vapier 1.70 return (be_wewy_wewy_quiet ? NULL : ret); \
211 vapier 1.39 } \
212     ++dyn; \
213 vapier 1.26 } \
214 vapier 1.39 } }
215     SHOW_TEXTREL(32)
216     SHOW_TEXTREL(64)
217 vapier 1.44 }
218    
219 vapier 1.70 if (be_quiet || be_wewy_wewy_quiet)
220 vapier 1.41 return NULL;
221     else
222 solar 1.68 return (char *)" - ";
223 vapier 1.39 }
224 vapier 1.76 static char *scanelf_file_textrels(elfobj *elf, char *found_textrels)
225     {
226     /* To locate TEXTREL symbols:
227     * for each shdr of type SHT_REL:
228     * for each phdr of type PT_LOAD:
229     * if phdr is not writable (why?)
230     * if shdr offset is inside of load (shdr->offset, phdr->{vaddr,memsz}
231     * look up shdr's symbol name
232     */
233     unsigned long p, s, r, rmax;
234     char *symtab_void, *strtab_void;
235    
236     if (!show_textrels) return NULL;
237    
238     /* debug sections */
239     symtab_void = elf_findsecbyname(elf, ".symtab");
240     strtab_void = elf_findsecbyname(elf, ".strtab");
241     /* fall back to runtime sections */
242     if (!symtab_void || !strtab_void) {
243     symtab_void = elf_findsecbyname(elf, ".dynsym");
244     strtab_void = elf_findsecbyname(elf, ".dynstr");
245     }
246    
247     if (elf->phdr && elf->shdr) {
248     #define SHOW_TEXTRELS(B) \
249     if (elf->elf_class == ELFCLASS ## B) { \
250     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
251     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
252     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
253     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
254     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
255     Elf ## B ## _Rel *rel; \
256     Elf ## B ## _Rela *rela; \
257     /* search the section headers for relocations */ \
258     for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
259     uint32_t sh_type = EGET(shdr[s].sh_type); \
260     if (sh_type == SHT_REL) { \
261     rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
262     rela = NULL; \
263     rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
264     } else if (sh_type == SHT_RELA) { \
265     rel = NULL; \
266     rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
267     rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
268     } else \
269     continue; \
270     /* search the program headers for PT_LOAD headers */ \
271     for (p = 0; p < EGET(ehdr->e_phnum); ++p) { \
272     Elf ## B ## _Addr vaddr; \
273     uint ## B ## _t memsz; \
274     if (EGET(phdr[p].p_type) != PT_LOAD) continue; \
275     if (EGET(phdr[p].p_flags) & PF_W) continue; \
276     vaddr = EGET(phdr[p].p_vaddr); \
277     memsz = EGET(phdr[p].p_memsz); \
278     *found_textrels = 1; \
279     /* now see if any of the relocs are in the PT_LOAD */ \
280     for (r = 0; r < rmax; ++r) { \
281     unsigned long sym_max; \
282     Elf ## B ## _Addr offset_tmp; \
283     Elf ## B ## _Sym *func; \
284     Elf ## B ## _Sym *sym; \
285     Elf ## B ## _Addr r_offset; \
286     uint ## B ## _t r_info; \
287     if (sh_type == SHT_REL) { \
288     r_offset = EGET(rel[r].r_offset); \
289     r_info = EGET(rel[r].r_info); \
290     } else { \
291     r_offset = EGET(rela[r].r_offset); \
292     r_info = EGET(rela[r].r_info); \
293     } \
294     /* make sure this relocation is inside of the .text */ \
295     if (r_offset < vaddr || r_offset >= vaddr + memsz) continue; \
296     sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
297     /* locate this relocation symbol name */ \
298     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
299     sym += ELF ## B ## _R_SYM(r_info); \
300     /* show the raw details about this reloc */ \
301     printf("\tTEXTREL %s: ", elf->base_filename); \
302     if (sym->st_name) \
303     printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
304     else \
305     printf("(NULL: fake?)"); \
306     printf(" [0x%lX]", (unsigned long)r_offset); \
307     /* now try to find the closest symbol that this rel is probably in */ \
308     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
309     func = NULL; \
310     offset_tmp = 0; \
311     while (sym_max--) { \
312     if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
313     func = sym; \
314     offset_tmp = EGET(sym->st_value); \
315     } \
316     ++sym; \
317     } \
318     printf(" in "); \
319     if (func && func->st_name) \
320     printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
321     else \
322     printf("(NULL: fake?)"); \
323     printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
324     } \
325     } \
326     } }
327     SHOW_TEXTRELS(32)
328     SHOW_TEXTRELS(64)
329     }
330    
331     return NULL;
332     }
333 vapier 1.41 static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
334 vapier 1.39 {
335 vapier 1.48 unsigned long i, s;
336     char *rpath, *runpath, **r;
337 vapier 1.39 void *strtbl_void;
338 vapier 1.10
339 vapier 1.39 if (!show_rpath) return;
340 vapier 1.10
341 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
342     rpath = runpath = NULL;
343 vapier 1.10
344 vapier 1.44 if (elf->phdr && strtbl_void) {
345 vapier 1.26 #define SHOW_RPATH(B) \
346     if (elf->elf_class == ELFCLASS ## B) { \
347     Elf ## B ## _Dyn *dyn; \
348     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
349     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
350     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
351 vapier 1.44 Elf ## B ## _Off offset; \
352 vapier 1.60 Elf ## B ## _Xword word; \
353 vapier 1.48 /* Scan all the program headers */ \
354 vapier 1.26 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
355 vapier 1.48 /* Just scan dynamic headers */ \
356 vapier 1.26 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
357 vapier 1.44 offset = EGET(phdr[i].p_offset); \
358     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
359 vapier 1.48 /* Just scan dynamic RPATH/RUNPATH headers */ \
360 vapier 1.44 dyn = DYN ## B (elf->data + offset); \
361 vapier 1.48 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
362     if (word == DT_RPATH) { \
363     r = &rpath; \
364     } else if (word == DT_RUNPATH) { \
365     r = &runpath; \
366     } else { \
367     ++dyn; \
368     continue; \
369     } \
370     /* Verify the memory is somewhat sane */ \
371     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
372 vapier 1.69 if (offset < (Elf ## B ## _Off)elf->len) { \
373 vapier 1.48 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
374     *r = (char*)(elf->data + offset); \
375     /* If quiet, don't output paths in ld.so.conf */ \
376 vapier 1.69 if (be_quiet) { \
377     size_t len; \
378     char *start, *end; \
379 vapier 1.75 /* note that we only 'chop' off leading known paths. */ \
380     /* since *r is read-only memory, we can only move the ptr forward. */ \
381     start = *r; \
382     /* scan each path in : delimited list */ \
383     while (start) { \
384 vapier 1.69 end = strchr(start, ':'); \
385 vapier 1.75 len = (end ? abs(end - start) : strlen(start)); \
386     for (s = 0; ldpaths[s]; ++s) { \
387 vapier 1.69 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
388     *r = (end ? end + 1 : NULL); \
389     break; \
390     } \
391 vapier 1.48 } \
392 vapier 1.75 if (!*r || !ldpaths[s] || !end) \
393     start = NULL; \
394     else \
395     start = start + len + 1; \
396 vapier 1.69 } \
397     } \
398 vapier 1.48 if (*r) *found_rpath = 1; \
399 vapier 1.26 } \
400     ++dyn; \
401     } \
402     } }
403     SHOW_RPATH(32)
404     SHOW_RPATH(64)
405 vapier 1.10 }
406 vapier 1.41
407 vapier 1.70 if (be_wewy_wewy_quiet) return;
408    
409 vapier 1.39 if (rpath && runpath) {
410 vapier 1.41 if (!strcmp(rpath, runpath)) {
411     xstrcat(ret, runpath, ret_len);
412     } else {
413 vapier 1.39 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
414 vapier 1.41 xchrcat(ret, '{', ret_len);
415     xstrcat(ret, rpath, ret_len);
416     xchrcat(ret, ',', ret_len);
417     xstrcat(ret, runpath, ret_len);
418     xchrcat(ret, '}', ret_len);
419 vapier 1.39 }
420     } else if (rpath || runpath)
421 vapier 1.41 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
422     else if (!be_quiet)
423     xstrcat(ret, " - ", ret_len);
424 vapier 1.39 }
425 vapier 1.72 static char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
426 vapier 1.39 {
427 vapier 1.44 unsigned long i;
428 vapier 1.39 char *needed;
429     void *strtbl_void;
430    
431 vapier 1.72 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
432 vapier 1.10
433 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
434 vapier 1.32
435 vapier 1.44 if (elf->phdr && strtbl_void) {
436 vapier 1.32 #define SHOW_NEEDED(B) \
437     if (elf->elf_class == ELFCLASS ## B) { \
438     Elf ## B ## _Dyn *dyn; \
439     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
440     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
441     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
442 vapier 1.44 Elf ## B ## _Off offset; \
443 vapier 1.32 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
444     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
445 vapier 1.44 offset = EGET(phdr[i].p_offset); \
446     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
447     dyn = DYN ## B (elf->data + offset); \
448 vapier 1.32 while (EGET(dyn->d_tag) != DT_NULL) { \
449     if (EGET(dyn->d_tag) == DT_NEEDED) { \
450 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
451 vapier 1.69 if (offset >= (Elf ## B ## _Off)elf->len) { \
452 vapier 1.49 ++dyn; \
453     continue; \
454     } \
455 vapier 1.44 needed = (char*)(elf->data + offset); \
456 vapier 1.72 if (op == 0) { \
457     if (!be_wewy_wewy_quiet) { \
458     if (*found_needed) xchrcat(ret, ',', ret_len); \
459     xstrcat(ret, needed, ret_len); \
460     } \
461     *found_needed = 1; \
462     } else { \
463     if (strcmp(find_lib, needed)) return NULL; \
464     *found_lib = 1; \
465     return (be_wewy_wewy_quiet ? NULL : find_lib); \
466     } \
467 vapier 1.32 } \
468     ++dyn; \
469     } \
470     } }
471     SHOW_NEEDED(32)
472     SHOW_NEEDED(64)
473     }
474 vapier 1.72
475     return NULL;
476 vapier 1.39 }
477 vapier 1.41 static char *scanelf_file_interp(elfobj *elf, char *found_interp)
478 vapier 1.39 {
479     void *strtbl_void;
480    
481 vapier 1.41 if (!show_interp) return NULL;
482 vapier 1.32
483 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".interp");
484 vapier 1.38
485 vapier 1.39 if (strtbl_void) {
486 vapier 1.38 #define SHOW_INTERP(B) \
487     if (elf->elf_class == ELFCLASS ## B) { \
488 solar 1.40 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
489     *found_interp = 1; \
490 vapier 1.70 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
491 vapier 1.38 }
492     SHOW_INTERP(32)
493     SHOW_INTERP(64)
494     }
495 vapier 1.41 return NULL;
496 vapier 1.39 }
497 vapier 1.49 static char *scanelf_file_bind(elfobj *elf, char *found_bind)
498     {
499     unsigned long i;
500     struct stat s;
501    
502     if (!show_bind) return NULL;
503 vapier 1.51 if (!elf->phdr) return NULL;
504 vapier 1.49
505     #define SHOW_BIND(B) \
506     if (elf->elf_class == ELFCLASS ## B) { \
507     Elf ## B ## _Dyn *dyn; \
508     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
509     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
510     Elf ## B ## _Off offset; \
511     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
512     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
513     offset = EGET(phdr[i].p_offset); \
514     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
515     dyn = DYN ## B (elf->data + offset); \
516     while (EGET(dyn->d_tag) != DT_NULL) { \
517     if (EGET(dyn->d_tag) == DT_BIND_NOW || \
518     (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
519     { \
520     if (be_quiet) return NULL; \
521     *found_bind = 1; \
522 vapier 1.70 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
523 vapier 1.49 } \
524     ++dyn; \
525     } \
526     } \
527     }
528     SHOW_BIND(32)
529     SHOW_BIND(64)
530    
531 vapier 1.70 if (be_wewy_wewy_quiet) return NULL;
532    
533 vapier 1.56 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
534 vapier 1.49 return NULL;
535     } else {
536     *found_bind = 1;
537 solar 1.68 return (char *) "LAZY";
538 vapier 1.49 }
539     }
540 vapier 1.72 static char *scanelf_file_sym(elfobj *elf, char *found_sym)
541 vapier 1.39 {
542 vapier 1.44 unsigned long i;
543 vapier 1.39 void *symtab_void, *strtab_void;
544 vapier 1.38
545 vapier 1.41 if (!find_sym) return NULL;
546 vapier 1.32
547 vapier 1.67 /* debug sections */
548 vapier 1.39 symtab_void = elf_findsecbyname(elf, ".symtab");
549     strtab_void = elf_findsecbyname(elf, ".strtab");
550 vapier 1.67 /* fall back to runtime sections */
551     if (!symtab_void || !strtab_void) {
552     symtab_void = elf_findsecbyname(elf, ".dynsym");
553     strtab_void = elf_findsecbyname(elf, ".dynstr");
554     }
555 vapier 1.27
556 vapier 1.39 if (symtab_void && strtab_void) {
557 vapier 1.27 #define FIND_SYM(B) \
558     if (elf->elf_class == ELFCLASS ## B) { \
559     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
560     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
561     Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
562 vapier 1.44 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
563 vapier 1.27 char *symname; \
564     for (i = 0; i < cnt; ++i) { \
565     if (sym->st_name) { \
566     symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
567 solar 1.28 if (*find_sym == '*') { \
568 vapier 1.32 printf("%s(%s) %5lX %15s %s\n", \
569 vapier 1.39 ((*found_sym == 0) ? "\n\t" : "\t"), \
570 vapier 1.76 elf->base_filename, \
571 vapier 1.32 (long)sym->st_size, \
572     (char *)get_elfstttype(sym->st_info), \
573     symname); \
574 vapier 1.39 *found_sym = 1; \
575 vapier 1.32 } else if ((strcmp(find_sym, symname) == 0) || \
576 vapier 1.39 (strcmp(symname, versioned_symname) == 0)) \
577     (*found_sym)++; \
578 vapier 1.27 } \
579     ++sym; \
580     } }
581     FIND_SYM(32)
582     FIND_SYM(64)
583 vapier 1.39 }
584 vapier 1.70
585     if (be_wewy_wewy_quiet) return NULL;
586    
587 vapier 1.41 if (*find_sym != '*' && *found_sym)
588     return find_sym;
589     if (be_quiet)
590     return NULL;
591     else
592 solar 1.68 return (char *)" - ";
593 vapier 1.39 }
594     /* scan an elf file and show all the fun stuff */
595 solar 1.57 #define prints(str) write(fileno(stdout), str, strlen(str))
596 vapier 1.39 static void scanelf_file(const char *filename)
597     {
598 vapier 1.44 unsigned long i;
599 solar 1.73 char found_pax, found_phdr, found_relro, found_load, found_textrel,
600 vapier 1.49 found_rpath, found_needed, found_interp, found_bind,
601 vapier 1.76 found_sym, found_lib, found_file, found_textrels;
602 vapier 1.39 elfobj *elf;
603     struct stat st;
604 vapier 1.41 static char *out_buffer = NULL;
605     static size_t out_len;
606 vapier 1.39
607     /* make sure 'filename' exists */
608     if (lstat(filename, &st) == -1) {
609     if (be_verbose > 2) printf("%s: does not exist\n", filename);
610     return;
611     }
612     /* always handle regular files and handle symlinked files if no -y */
613 vapier 1.55 if (S_ISLNK(st.st_mode)) {
614     if (!scan_symlink) return;
615     stat(filename, &st);
616     }
617     if (!S_ISREG(st.st_mode)) {
618 vapier 1.39 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
619     return;
620     }
621    
622 vapier 1.76 found_pax = found_phdr = found_relro = found_load = found_textrel = \
623     found_rpath = found_needed = found_interp = found_bind = \
624     found_sym = found_lib = found_file = found_textrels = 0;
625 vapier 1.39
626     /* verify this is real ELF */
627     if ((elf = readelf(filename)) == NULL) {
628     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
629     return;
630     }
631    
632     if (be_verbose > 1)
633 vapier 1.41 printf("%s: scanning file {%s,%s}\n", filename,
634 vapier 1.69 get_elfeitype(EI_CLASS, elf->elf_class),
635     get_elfeitype(EI_DATA, elf->data[EI_DATA]));
636 vapier 1.39 else if (be_verbose)
637     printf("%s: scanning file\n", filename);
638    
639 vapier 1.41 /* init output buffer */
640     if (!out_buffer) {
641     out_len = sizeof(char) * 80;
642     out_buffer = (char*)xmalloc(out_len);
643     }
644     *out_buffer = '\0';
645    
646 vapier 1.39 /* show the header */
647     if (!be_quiet && show_banner) {
648 vapier 1.49 for (i = 0; out_format[i]; ++i) {
649 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
650 vapier 1.41
651     switch (out_format[++i]) {
652     case '%': break;
653 vapier 1.70 case '#': break;
654 vapier 1.66 case 'F':
655     case 'p':
656     case 'f': prints("FILE "); found_file = 1; break;
657 vapier 1.41 case 'o': prints(" TYPE "); break;
658     case 'x': prints(" PAX "); break;
659 vapier 1.71 case 'e': prints("STK/REL/PTL "); break;
660 vapier 1.41 case 't': prints("TEXTREL "); break;
661     case 'r': prints("RPATH "); break;
662     case 'n': prints("NEEDED "); break;
663     case 'i': prints("INTERP "); break;
664 vapier 1.49 case 'b': prints("BIND "); break;
665 vapier 1.41 case 's': prints("SYM "); break;
666 vapier 1.72 case 'N': prints("LIB "); break;
667 vapier 1.76 case 'T': prints("TEXTRELS "); break;
668     default: warnf("'%c' has no title ?", out_format[i]);
669 vapier 1.39 }
670 vapier 1.27 }
671 vapier 1.49 if (!found_file) prints("FILE ");
672 vapier 1.41 prints("\n");
673 vapier 1.49 found_file = 0;
674 vapier 1.39 show_banner = 0;
675     }
676    
677     /* dump all the good stuff */
678 vapier 1.49 for (i = 0; out_format[i]; ++i) {
679 vapier 1.41 const char *out;
680 vapier 1.66 const char *tmp;
681 vapier 1.41
682     /* make sure we trim leading spaces in quiet mode */
683     if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
684     *out_buffer = '\0';
685 vapier 1.39
686 vapier 1.70 if (!IS_MODIFIER(out_format[i])) {
687 vapier 1.41 xchrcat(&out_buffer, out_format[i], &out_len);
688     continue;
689     }
690 vapier 1.39
691 vapier 1.41 out = NULL;
692 vapier 1.70 be_wewy_wewy_quiet = (out_format[i] == '#');
693 vapier 1.41 switch (out_format[++i]) {
694 vapier 1.70 case '%':
695     case '#':
696     xchrcat(&out_buffer, out_format[i], &out_len); break;
697     case 'F':
698 vapier 1.76 found_file = 1;
699 vapier 1.70 if (be_wewy_wewy_quiet) break;
700     xstrcat(&out_buffer, filename, &out_len);
701     break;
702 vapier 1.66 case 'p':
703 vapier 1.76 found_file = 1;
704 vapier 1.70 if (be_wewy_wewy_quiet) break;
705 vapier 1.66 tmp = filename;
706     if (search_path) {
707     ssize_t len_search = strlen(search_path);
708     ssize_t len_file = strlen(filename);
709     if (!strncmp(filename, search_path, len_search) && \
710     len_file > len_search)
711     tmp += len_search;
712     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
713     }
714     xstrcat(&out_buffer, tmp, &out_len);
715     break;
716     case 'f':
717 vapier 1.76 found_file = 1;
718 vapier 1.70 if (be_wewy_wewy_quiet) break;
719 vapier 1.66 tmp = strrchr(filename, '/');
720     tmp = (tmp == NULL ? filename : tmp+1);
721     xstrcat(&out_buffer, tmp, &out_len);
722     break;
723 vapier 1.41 case 'o': out = get_elfetype(elf); break;
724     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
725 solar 1.73 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
726 vapier 1.41 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
727 vapier 1.76 case 'T': out = scanelf_file_textrels(elf, &found_textrels); break;
728 vapier 1.41 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
729 vapier 1.72 case 'n':
730     case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
731 vapier 1.41 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
732 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
733 vapier 1.72 case 's': out = scanelf_file_sym(elf, &found_sym); break;
734 vapier 1.76 default: warnf("'%c' has no scan code?", out_format[i]);
735 vapier 1.29 }
736 vapier 1.41 if (out) xstrcat(&out_buffer, out, &out_len);
737 vapier 1.39 }
738    
739 vapier 1.54 #define FOUND_SOMETHING() \
740 solar 1.73 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
741 vapier 1.76 found_rpath || found_needed || found_interp || found_bind || \
742     found_sym || found_lib || found_textrels)
743 vapier 1.54
744     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
745     xchrcat(&out_buffer, ' ', &out_len);
746     xstrcat(&out_buffer, filename, &out_len);
747 vapier 1.27 }
748 vapier 1.54 if (!be_quiet || (be_quiet && FOUND_SOMETHING()))
749 vapier 1.41 puts(out_buffer);
750 vapier 1.10
751     unreadelf(elf);
752 solar 1.6 }
753    
754 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
755 vapier 1.10 static void scanelf_dir(const char *path)
756 solar 1.1 {
757 vapier 1.10 register DIR *dir;
758     register struct dirent *dentry;
759 vapier 1.14 struct stat st_top, st;
760 solar 1.21 char buf[_POSIX_PATH_MAX];
761 vapier 1.32 size_t pathlen = 0, len = 0;
762 vapier 1.10
763     /* make sure path exists */
764 vapier 1.39 if (lstat(path, &st_top) == -1) {
765     if (be_verbose > 2) printf("%s: does not exist\n", path);
766 vapier 1.10 return;
767 vapier 1.39 }
768 solar 1.11
769 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
770 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
771 vapier 1.10 scanelf_file(path);
772     return;
773     }
774    
775     /* now scan the dir looking for fun stuff */
776     if ((dir = opendir(path)) == NULL) {
777     warnf("could not opendir %s: %s", path, strerror(errno));
778     return;
779     }
780 vapier 1.15 if (be_verbose) printf("%s: scanning dir\n", path);
781 solar 1.11
782 vapier 1.32 pathlen = strlen(path);
783 vapier 1.10 while ((dentry = readdir(dir))) {
784     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
785     continue;
786 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
787     if (len >= sizeof(buf)) {
788 vapier 1.76 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
789     (unsigned long)len, (unsigned long)sizeof(buf));
790 vapier 1.32 continue;
791     }
792 solar 1.31 sprintf(buf, "%s/%s", path, dentry->d_name);
793 solar 1.20 if (lstat(buf, &st) != -1) {
794 vapier 1.10 if (S_ISREG(st.st_mode))
795 solar 1.20 scanelf_file(buf);
796 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
797 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
798 solar 1.20 scanelf_dir(buf);
799 vapier 1.10 }
800     }
801     }
802     closedir(dir);
803 solar 1.1 }
804    
805 vapier 1.47 static int scanelf_from_file(char *filename)
806     {
807 solar 1.45 FILE *fp = NULL;
808     char *p;
809     char path[_POSIX_PATH_MAX];
810    
811     if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
812     fp = stdin;
813     else if ((fp = fopen(filename, "r")) == NULL)
814     return 1;
815    
816     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
817     if ((p = strchr(path, '\n')) != NULL)
818     *p = 0;
819 vapier 1.66 search_path = path;
820 solar 1.45 scanelf_dir(path);
821     }
822     if (fp != stdin)
823     fclose(fp);
824     return 0;
825     }
826    
827 vapier 1.48 static void load_ld_so_conf()
828     {
829     FILE *fp = NULL;
830     char *p;
831     char path[_POSIX_PATH_MAX];
832     int i = 0;
833    
834     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
835     return;
836    
837     while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
838     if (*path != '/')
839     continue;
840    
841     if ((p = strrchr(path, '\r')) != NULL)
842     *p = 0;
843     if ((p = strchr(path, '\n')) != NULL)
844     *p = 0;
845    
846     ldpaths[i++] = xstrdup(path);
847    
848     if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
849     break;
850     }
851     ldpaths[i] = NULL;
852    
853     fclose(fp);
854     }
855    
856 vapier 1.10 /* scan /etc/ld.so.conf for paths */
857     static void scanelf_ldpath()
858     {
859 vapier 1.17 char scan_l, scan_ul, scan_ull;
860 vapier 1.48 int i = 0;
861 vapier 1.10
862 vapier 1.48 if (!ldpaths[0])
863     err("Unable to load any paths from ld.so.conf");
864 vapier 1.10
865 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
866    
867 vapier 1.48 while (ldpaths[i]) {
868     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
869     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
870     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
871     scanelf_dir(ldpaths[i]);
872     ++i;
873     }
874 vapier 1.10
875 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
876     if (!scan_ul) scanelf_dir("/usr/lib");
877     if (!scan_ull) scanelf_dir("/usr/local/lib");
878 vapier 1.10 }
879 solar 1.1
880 vapier 1.10 /* scan env PATH for paths */
881     static void scanelf_envpath()
882 solar 1.1 {
883 solar 1.34 char *path, *p;
884 vapier 1.10
885     path = getenv("PATH");
886     if (!path)
887     err("PATH is not set in your env !");
888 vapier 1.41 path = xstrdup(path);
889 vapier 1.10
890     while ((p = strrchr(path, ':')) != NULL) {
891     scanelf_dir(p + 1);
892     *p = 0;
893     }
894 vapier 1.17
895 solar 1.34 free(path);
896 solar 1.1 }
897    
898    
899 vapier 1.10
900     /* usage / invocation handling functions */
901 vapier 1.76 #define PARSE_FLAGS "plRmyxetrnibs:N:TaqvF:f:o:BhV"
902 vapier 1.27 #define a_argument required_argument
903 vapier 1.10 static struct option const long_opts[] = {
904     {"path", no_argument, NULL, 'p'},
905     {"ldpath", no_argument, NULL, 'l'},
906     {"recursive", no_argument, NULL, 'R'},
907 vapier 1.14 {"mount", no_argument, NULL, 'm'},
908 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
909 vapier 1.10 {"pax", no_argument, NULL, 'x'},
910 solar 1.16 {"header", no_argument, NULL, 'e'},
911 vapier 1.10 {"textrel", no_argument, NULL, 't'},
912     {"rpath", no_argument, NULL, 'r'},
913 vapier 1.32 {"needed", no_argument, NULL, 'n'},
914 vapier 1.38 {"interp", no_argument, NULL, 'i'},
915 vapier 1.49 {"bind", no_argument, NULL, 'b'},
916 vapier 1.76 {"symbol", a_argument, NULL, 's'},
917     {"lib", a_argument, NULL, 'N'},
918     {"textrels", no_argument, NULL, 'T'},
919 vapier 1.10 {"all", no_argument, NULL, 'a'},
920     {"quiet", no_argument, NULL, 'q'},
921 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
922 vapier 1.76 {"format", a_argument, NULL, 'F'},
923     {"from", a_argument, NULL, 'f'},
924     {"file", a_argument, NULL, 'o'},
925 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
926 vapier 1.10 {"help", no_argument, NULL, 'h'},
927     {"version", no_argument, NULL, 'V'},
928     {NULL, no_argument, NULL, 0x0}
929     };
930 solar 1.57
931 solar 1.68 static const char *opts_help[] = {
932 vapier 1.10 "Scan all directories in PATH environment",
933     "Scan all directories in /etc/ld.so.conf",
934 vapier 1.14 "Scan directories recursively",
935 vapier 1.37 "Don't recursively cross mount points",
936     "Don't scan symlinks\n",
937 vapier 1.10 "Print PaX markings",
938 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
939 vapier 1.10 "Print TEXTREL information",
940     "Print RPATH information",
941 vapier 1.32 "Print NEEDED information",
942 vapier 1.38 "Print INTERP information",
943 vapier 1.49 "Print BIND information",
944 vapier 1.27 "Find a specified symbol",
945 vapier 1.72 "Find a specified library",
946 vapier 1.76 "Locate cause of TEXTREL",
947 solar 1.57 "Print all scanned info (-x -e -t -r -n -i -b)\n",
948 vapier 1.14 "Only output 'bad' things",
949     "Be verbose (can be specified more than once)",
950 vapier 1.39 "Use specified format for output",
951 solar 1.45 "Read input stream from a filename",
952 vapier 1.24 "Write output stream to a filename",
953 vapier 1.14 "Don't display the header",
954 vapier 1.10 "Print this help and exit",
955     "Print version and exit",
956     NULL
957     };
958    
959     /* display usage and exit */
960     static void usage(int status)
961 solar 1.1 {
962 vapier 1.44 unsigned long i;
963 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
964 solar 1.35 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
965     printf("Options: -[%s]\n", PARSE_FLAGS);
966 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
967 vapier 1.27 if (long_opts[i].has_arg == no_argument)
968 solar 1.52 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
969 vapier 1.27 long_opts[i].name, opts_help[i]);
970     else
971 solar 1.52 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
972 vapier 1.27 long_opts[i].name, opts_help[i]);
973 solar 1.45
974     if (status != EXIT_SUCCESS)
975     exit(status);
976    
977 vapier 1.46 puts("\nThe format modifiers for the -F option are:");
978 vapier 1.70 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
979     puts(" t TEXTREL \tr RPATH \tn NEEDED");
980     puts(" i INTERP \tb BIND \ts symbol");
981 vapier 1.76 puts(" N library \to Type \tT TEXTRELs");
982 vapier 1.70 puts(" p filename (with search path removed)");
983     puts(" f base filename");
984     puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
985 solar 1.45
986 vapier 1.10 exit(status);
987 solar 1.1 }
988    
989     /* parse command line arguments and preform needed actions */
990 vapier 1.10 static void parseargs(int argc, char *argv[])
991     {
992 vapier 1.48 int i;
993 solar 1.45 char *from_file = NULL;
994 vapier 1.10
995     opterr = 0;
996 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
997     switch (i) {
998 vapier 1.10
999 vapier 1.39 case 'V':
1000 solar 1.19 printf("%s compiled %s\n%s\n"
1001     "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
1002     __FILE__, __DATE__, rcsid, argv0);
1003 vapier 1.10 exit(EXIT_SUCCESS);
1004     break;
1005     case 'h': usage(EXIT_SUCCESS); break;
1006 solar 1.45 case 'f':
1007 solar 1.64 if (from_file) err("Don't specify -f twice");
1008     from_file = xstrdup(optarg);
1009 solar 1.45 break;
1010 vapier 1.24 case 'o': {
1011 solar 1.21 FILE *fp = NULL;
1012 solar 1.64 if ((fp = freopen(optarg, "w", stdout)) == NULL)
1013 vapier 1.24 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1014 vapier 1.65 SET_STDOUT(fp);
1015 solar 1.21 break;
1016     }
1017 vapier 1.24
1018 vapier 1.39 case 's': {
1019     size_t len;
1020 solar 1.64 if (find_sym) err("Don't specify -s twice");
1021 vapier 1.41 find_sym = xstrdup(optarg);
1022 vapier 1.39 len = strlen(find_sym) + 1;
1023 vapier 1.41 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
1024 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
1025     break;
1026     }
1027 vapier 1.72 case 'N': {
1028     if (find_lib) err("Don't specify -N twice");
1029     find_lib = xstrdup(optarg);
1030     break;
1031     }
1032 vapier 1.39
1033     case 'F': {
1034 solar 1.64 if (out_format) err("Don't specify -F twice");
1035     out_format = xstrdup(optarg);
1036 vapier 1.39 break;
1037     }
1038 vapier 1.27
1039 vapier 1.37 case 'y': scan_symlink = 0; break;
1040 solar 1.16 case 'B': show_banner = 0; break;
1041 vapier 1.10 case 'l': scan_ldpath = 1; break;
1042     case 'p': scan_envpath = 1; break;
1043     case 'R': dir_recurse = 1; break;
1044 vapier 1.14 case 'm': dir_crossmount = 0; break;
1045 vapier 1.10 case 'x': show_pax = 1; break;
1046 solar 1.73 case 'e': show_phdr = 1; break;
1047 vapier 1.10 case 't': show_textrel = 1; break;
1048     case 'r': show_rpath = 1; break;
1049 vapier 1.32 case 'n': show_needed = 1; break;
1050 vapier 1.38 case 'i': show_interp = 1; break;
1051 vapier 1.49 case 'b': show_bind = 1; break;
1052 vapier 1.76 case 'T': show_textrels = 1; break;
1053 vapier 1.10 case 'q': be_quiet = 1; break;
1054 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1055 solar 1.73 case 'a': show_pax = show_phdr = show_textrel = show_rpath = \
1056 vapier 1.50 show_needed = show_interp = show_bind = 1; break;
1057 vapier 1.10
1058     case ':':
1059 vapier 1.49 err("Option missing parameter\n");
1060 vapier 1.10 case '?':
1061 vapier 1.49 err("Unknown option\n");
1062 vapier 1.10 default:
1063 vapier 1.48 err("Unhandled option '%c'", i);
1064 vapier 1.10 }
1065     }
1066    
1067 vapier 1.39 /* let the format option override all other options */
1068     if (out_format) {
1069 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1070 vapier 1.76 show_needed = show_interp = show_bind = show_textrels = 0;
1071 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1072 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1073 vapier 1.39
1074 vapier 1.48 switch (out_format[++i]) {
1075 vapier 1.39 case '%': break;
1076 vapier 1.70 case '#': break;
1077 vapier 1.39 case 'F': break;
1078 vapier 1.66 case 'p': break;
1079     case 'f': break;
1080 vapier 1.39 case 's': break;
1081 vapier 1.72 case 'N': break;
1082 vapier 1.41 case 'o': break;
1083 vapier 1.39 case 'x': show_pax = 1; break;
1084 solar 1.73 case 'e': show_phdr = 1; break;
1085 vapier 1.39 case 't': show_textrel = 1; break;
1086     case 'r': show_rpath = 1; break;
1087     case 'n': show_needed = 1; break;
1088     case 'i': show_interp = 1; break;
1089 vapier 1.49 case 'b': show_bind = 1; break;
1090 vapier 1.76 case 'T': show_textrels = 1; break;
1091 vapier 1.39 default:
1092     err("Invalid format specifier '%c' (byte %i)",
1093 vapier 1.48 out_format[i], i+1);
1094 vapier 1.39 }
1095     }
1096 vapier 1.41
1097     /* construct our default format */
1098     } else {
1099     size_t fmt_len = 30;
1100     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1101 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1102     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1103     if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1104     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1105     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1106     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1107     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1108     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1109     if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1110     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1111     if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1112     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1113 vapier 1.39 }
1114 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1115 vapier 1.39
1116     /* now lets actually do the scanning */
1117 vapier 1.48 if (scan_ldpath || (show_rpath && be_quiet))
1118     load_ld_so_conf();
1119 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1120     if (scan_envpath) scanelf_envpath();
1121 solar 1.45 if (from_file) {
1122     scanelf_from_file(from_file);
1123     free(from_file);
1124     from_file = *argv;
1125     }
1126     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1127 vapier 1.25 err("Nothing to scan !?");
1128 vapier 1.66 while (optind < argc) {
1129     search_path = argv[optind++];
1130     scanelf_dir(search_path);
1131     }
1132 vapier 1.27
1133 vapier 1.39 /* clean up */
1134     if (find_sym) {
1135     free(find_sym);
1136     free(versioned_symname);
1137     }
1138 vapier 1.72 if (find_lib) free(find_lib);
1139 vapier 1.39 if (out_format) free(out_format);
1140 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1141     free(ldpaths[i]);
1142 vapier 1.10 }
1143    
1144    
1145    
1146 vapier 1.41 /* utility funcs */
1147 vapier 1.60 static char *xstrdup(const char *s)
1148 vapier 1.41 {
1149     char *ret = strdup(s);
1150     if (!ret) err("Could not strdup(): %s", strerror(errno));
1151     return ret;
1152     }
1153 solar 1.57
1154 vapier 1.41 static void *xmalloc(size_t size)
1155     {
1156     void *ret = malloc(size);
1157     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1158     return ret;
1159     }
1160 solar 1.57
1161 vapier 1.41 static void xstrcat(char **dst, const char *src, size_t *curr_len)
1162     {
1163 vapier 1.69 size_t new_len;
1164 vapier 1.41
1165     new_len = strlen(*dst) + strlen(src);
1166     if (*curr_len <= new_len) {
1167     *curr_len = new_len + (*curr_len / 2);
1168     *dst = realloc(*dst, *curr_len);
1169     if (!*dst)
1170     err("could not realloc %li bytes", (unsigned long)*curr_len);
1171     }
1172    
1173     strcat(*dst, src);
1174     }
1175 solar 1.57
1176 vapier 1.41 static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1177     {
1178     static char my_app[2];
1179     my_app[0] = append;
1180     my_app[1] = '\0';
1181     xstrcat(dst, my_app, curr_len);
1182     }
1183    
1184    
1185 vapier 1.72
1186 vapier 1.10 int main(int argc, char *argv[])
1187 solar 1.1 {
1188 vapier 1.10 if (argc < 2)
1189     usage(EXIT_FAILURE);
1190     parseargs(argc, argv);
1191 solar 1.21 fclose(stdout);
1192 solar 1.61 #ifdef __BOUNDS_CHECKING_ON
1193 vapier 1.66 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
1194 solar 1.61 #endif
1195 vapier 1.10 return EXIT_SUCCESS;
1196 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20