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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.81 - (hide annotations) (download) (as text)
Mon Jun 13 03:35:41 2005 UTC (9 years, 2 months ago) by vapier
Branch: MAIN
Changes since 1.80: +6 -5 lines
File MIME type: text/x-csrc
make sure we check all the libraries a file needs instead of just the first one (-N)

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

  ViewVC Help
Powered by ViewVC 1.1.20