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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.74 - (hide annotations) (download) (as text)
Sun Jun 5 09:42:06 2005 UTC (9 years, 2 months ago) by vapier
Branch: MAIN
Changes since 1.73: +3 -3 lines
File MIME type: text/x-csrc
fix warning in printf

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

  ViewVC Help
Powered by ViewVC 1.1.20