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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.75 - (hide annotations) (download) (as text)
Mon Jun 6 23:32:38 2005 UTC (9 years, 1 month ago) by vapier
Branch: MAIN
Changes since 1.74: +13 -8 lines
File MIME type: text/x-csrc
fix runpath parsing in quiet mode

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

  ViewVC Help
Powered by ViewVC 1.1.20