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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.80 - (hide annotations) (download) (as text)
Mon Jun 13 03:09:51 2005 UTC (9 years, 1 month ago) by vapier
Branch: MAIN
Changes since 1.79: +5 -5 lines
File MIME type: text/x-csrc
tweak version output to include $PV

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

  ViewVC Help
Powered by ViewVC 1.1.20