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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.77 - (hide annotations) (download) (as text)
Wed Jun 8 05:43:01 2005 UTC (9 years, 2 months ago) by vapier
Branch: MAIN
Changes since 1.76: +39 -30 lines
File MIME type: text/x-csrc
make sure REL is an offset inside the symtab before using and create a func to pick the better sym/tab headers based on size

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

  ViewVC Help
Powered by ViewVC 1.1.20