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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.82 - (hide annotations) (download) (as text)
Sun Jun 19 05:39:31 2005 UTC (10 years, 2 months ago) by vapier
Branch: MAIN
Changes since 1.81: +62 -67 lines
File MIME type: text/x-csrc
change textrel scanner to check .text section instead of PT_LOAD ... also update -a to not include bind/interp info

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

  ViewVC Help
Powered by ViewVC 1.1.20