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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.116 - (hide annotations) (download) (as text)
Sat Jan 28 18:54:08 2006 UTC (8 years, 9 months ago) by solar
Branch: MAIN
Changes since 1.115: +5 -3 lines
File MIME type: text/x-csrc
- reset ldcache to 0 if set to -1 so we dont end up trying to memcmp later

1 solar 1.1 /*
2 vapier 1.98 * Copyright 2003-2006 Gentoo Foundation
3 solar 1.1 * Distributed under the terms of the GNU General Public License v2
4 solar 1.116 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.115 2006/01/24 00:34:00 vapier Exp $
5 solar 1.1 *
6 vapier 1.98 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
7     * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
8 solar 1.1 */
9    
10 vapier 1.89 #include "paxinc.h"
11 solar 1.1
12 solar 1.116 static const char *rcsid = "$Id: scanelf.c,v 1.115 2006/01/24 00:34:00 vapier Exp $";
13 vapier 1.36 #define argv0 "scanelf"
14 vapier 1.10
15 vapier 1.70 #define IS_MODIFIER(c) (c == '%' || c == '#')
16    
17 vapier 1.10
18    
19     /* prototypes */
20 vapier 1.106 static int scanelf_elfobj(elfobj *elf);
21     static int scanelf_elf(const char *filename, int fd, size_t len);
22     static int scanelf_archive(const char *filename, int fd, size_t len);
23 vapier 1.10 static void scanelf_file(const char *filename);
24     static void scanelf_dir(const char *path);
25 vapier 1.106 static void scanelf_ldpath(void);
26     static void scanelf_envpath(void);
27 vapier 1.10 static void usage(int status);
28     static void parseargs(int argc, char *argv[]);
29 vapier 1.60 static char *xstrdup(const char *s);
30 vapier 1.41 static void *xmalloc(size_t size);
31 vapier 1.95 static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
32     #define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
33 vapier 1.41 static inline void xchrcat(char **dst, const char append, size_t *curr_len);
34 vapier 1.10
35     /* variables to control behavior */
36 vapier 1.48 static char *ldpaths[256];
37 vapier 1.10 static char scan_ldpath = 0;
38     static char scan_envpath = 0;
39 vapier 1.37 static char scan_symlink = 1;
40 vapier 1.105 static char scan_archives = 0;
41 vapier 1.10 static char dir_recurse = 0;
42 vapier 1.14 static char dir_crossmount = 1;
43 vapier 1.10 static char show_pax = 0;
44 solar 1.73 static char show_phdr = 0;
45 vapier 1.10 static char show_textrel = 0;
46     static char show_rpath = 0;
47 vapier 1.32 static char show_needed = 0;
48 vapier 1.38 static char show_interp = 0;
49 vapier 1.49 static char show_bind = 0;
50 vapier 1.84 static char show_soname = 0;
51 vapier 1.76 static char show_textrels = 0;
52 solar 1.16 static char show_banner = 1;
53 vapier 1.10 static char be_quiet = 0;
54 vapier 1.14 static char be_verbose = 0;
55 vapier 1.70 static char be_wewy_wewy_quiet = 0;
56 vapier 1.39 static char *find_sym = NULL, *versioned_symname = NULL;
57 vapier 1.72 static char *find_lib = NULL;
58 vapier 1.39 static char *out_format = NULL;
59 vapier 1.66 static char *search_path = NULL;
60 vapier 1.101 static char fix_elf = 0;
61 solar 1.86 static char gmatch = 0;
62 vapier 1.102 static char use_ldcache = 0;
63 solar 1.1
64 vapier 1.70
65 solar 1.96 caddr_t ldcache = 0;
66     size_t ldcache_size = 0;
67    
68 vapier 1.39 /* sub-funcs for scanelf_file() */
69 vapier 1.77 static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
70     {
71     /* find the best SHT_DYNSYM and SHT_STRTAB sections */
72     #define GET_SYMTABS(B) \
73     if (elf->elf_class == ELFCLASS ## B) { \
74     Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
75     /* debug sections */ \
76     symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
77     strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
78     /* runtime sections */ \
79     dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
80     dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
81     if (symtab && dynsym) { \
82     *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
83     } else { \
84     *sym = (void*)(symtab ? symtab : dynsym); \
85     } \
86     if (strtab && dynstr) { \
87     *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
88     } else { \
89     *tab = (void*)(strtab ? strtab : dynstr); \
90     } \
91     }
92     GET_SYMTABS(32)
93     GET_SYMTABS(64)
94     }
95 vapier 1.41 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
96 solar 1.6 {
97 solar 1.61 static char ret[7];
98     unsigned long i, shown;
99    
100 vapier 1.41 if (!show_pax) return NULL;
101 vapier 1.10
102 solar 1.61 shown = 0;
103     memset(&ret, 0, sizeof(ret));
104    
105     if (elf->phdr) {
106     #define SHOW_PAX(B) \
107     if (elf->elf_class == ELFCLASS ## B) { \
108     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
109     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
110     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
111     if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
112     continue; \
113     if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
114     continue; \
115     memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
116     *found_pax = 1; \
117     ++shown; \
118     break; \
119     } \
120     }
121     SHOW_PAX(32)
122     SHOW_PAX(64)
123     }
124    
125     /* fall back to EI_PAX if no PT_PAX was found */
126     if (!*ret) {
127 vapier 1.90 static char *paxflags;
128 solar 1.61 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
129     if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
130     *found_pax = 1;
131 vapier 1.90 return (be_wewy_wewy_quiet ? NULL : paxflags);
132 solar 1.61 }
133     strncpy(ret, paxflags, sizeof(ret));
134 vapier 1.14 }
135 vapier 1.41
136 vapier 1.90 if (be_wewy_wewy_quiet || (be_quiet && !shown))
137 solar 1.61 return NULL;
138 vapier 1.90 else
139     return ret;
140     }
141 solar 1.61
142 solar 1.73 static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
143 vapier 1.39 {
144 vapier 1.71 static char ret[12];
145 vapier 1.41 char *found;
146 vapier 1.99 unsigned long i, shown, multi_stack, multi_relro, multi_load;
147     int max_pt_load;
148 vapier 1.41
149 solar 1.73 if (!show_phdr) return NULL;
150 vapier 1.41
151 vapier 1.71 memcpy(ret, "--- --- ---\0", 12);
152    
153 vapier 1.41 shown = 0;
154 vapier 1.71 multi_stack = multi_relro = multi_load = 0;
155 vapier 1.99 max_pt_load = elf_max_pt_load(elf);
156 vapier 1.44
157 vapier 1.108 #define NOTE_GNU_STACK ".note.GNU-stack"
158 solar 1.73 #define SHOW_PHDR(B) \
159 vapier 1.39 if (elf->elf_class == ELFCLASS ## B) { \
160     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
161 vapier 1.91 Elf ## B ## _Off offset; \
162     uint32_t flags, check_flags; \
163     if (elf->phdr != NULL) { \
164     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
165     for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
166     if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
167     if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
168     found = found_phdr; \
169     offset = 0; \
170     check_flags = PF_X; \
171     } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
172     if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
173     found = found_relro; \
174     offset = 4; \
175     check_flags = PF_X; \
176     } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
177 vapier 1.99 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
178 vapier 1.91 found = found_load; \
179     offset = 8; \
180     check_flags = PF_W|PF_X; \
181     } else \
182     continue; \
183     flags = EGET(phdr[i].p_flags); \
184     if (be_quiet && ((flags & check_flags) != check_flags)) \
185     continue; \
186 vapier 1.101 if (fix_elf && ((flags & PF_X) != flags)) { \
187     ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
188     ret[3] = ret[7] = '!'; \
189     flags = EGET(phdr[i].p_flags); \
190     } \
191 vapier 1.91 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
192     *found = 1; \
193     ++shown; \
194     } \
195     } else if (elf->shdr != NULL) { \
196     /* no program headers which means this is prob an object file */ \
197     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
198     Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
199 vapier 1.108 char *str; \
200     if ((void*)strtbl > (void*)(elf->data + sizeof(*strtbl))) \
201     goto skip_this_shdr##B; \
202 vapier 1.91 check_flags = SHF_WRITE|SHF_EXECINSTR; \
203     for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
204     if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
205     offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
206 vapier 1.108 str = elf->data + offset; \
207     if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
208     if (!strcmp(str, NOTE_GNU_STACK)) { \
209 vapier 1.91 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
210     flags = EGET(shdr[i].sh_flags); \
211     if (be_quiet && ((flags & check_flags) != check_flags)) \
212     continue; \
213     ++*found_phdr; \
214     shown = 1; \
215     if (flags & SHF_WRITE) ret[0] = 'W'; \
216     if (flags & SHF_ALLOC) ret[1] = 'A'; \
217     if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
218     if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
219     break; \
220     } \
221     } \
222 vapier 1.108 skip_this_shdr##B: \
223 vapier 1.91 if (!multi_stack) { \
224     *found_phdr = 1; \
225     shown = 1; \
226     memcpy(ret, "!WX", 3); \
227     } \
228 vapier 1.39 } \
229     }
230 solar 1.73 SHOW_PHDR(32)
231     SHOW_PHDR(64)
232 vapier 1.44
233 vapier 1.90 if (be_wewy_wewy_quiet || (be_quiet && !shown))
234 vapier 1.41 return NULL;
235     else
236     return ret;
237 vapier 1.39 }
238 vapier 1.90 static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
239 vapier 1.39 {
240 vapier 1.90 static const char *ret = "TEXTREL";
241 vapier 1.44 unsigned long i;
242 vapier 1.41
243 vapier 1.79 if (!show_textrel && !show_textrels) return NULL;
244 vapier 1.41
245 vapier 1.44 if (elf->phdr) {
246 vapier 1.39 #define SHOW_TEXTREL(B) \
247     if (elf->elf_class == ELFCLASS ## B) { \
248     Elf ## B ## _Dyn *dyn; \
249     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
250     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
251 vapier 1.44 Elf ## B ## _Off offset; \
252 vapier 1.39 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
253 vapier 1.59 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
254 vapier 1.44 offset = EGET(phdr[i].p_offset); \
255     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
256     dyn = DYN ## B (elf->data + offset); \
257 vapier 1.39 while (EGET(dyn->d_tag) != DT_NULL) { \
258     if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
259     *found_textrel = 1; \
260     /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
261 vapier 1.70 return (be_wewy_wewy_quiet ? NULL : ret); \
262 vapier 1.39 } \
263     ++dyn; \
264 vapier 1.26 } \
265 vapier 1.39 } }
266     SHOW_TEXTREL(32)
267     SHOW_TEXTREL(64)
268 vapier 1.44 }
269    
270 vapier 1.70 if (be_quiet || be_wewy_wewy_quiet)
271 vapier 1.41 return NULL;
272     else
273 vapier 1.90 return " - ";
274 vapier 1.39 }
275 vapier 1.79 static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
276 vapier 1.76 {
277 vapier 1.82 unsigned long s, r, rmax;
278     void *symtab_void, *strtab_void, *text_void;
279 vapier 1.76
280     if (!show_textrels) return NULL;
281    
282 vapier 1.79 /* don't search for TEXTREL's if the ELF doesn't have any */
283     if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
284     if (!*found_textrel) return NULL;
285    
286 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
287 vapier 1.82 text_void = elf_findsecbyname(elf, ".text");
288 vapier 1.76
289 vapier 1.82 if (symtab_void && strtab_void && text_void && elf->shdr) {
290 vapier 1.76 #define SHOW_TEXTRELS(B) \
291     if (elf->elf_class == ELFCLASS ## B) { \
292     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
293     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
294     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
295     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
296 vapier 1.82 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
297     Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
298     uint ## B ## _t memsz = EGET(text->sh_size); \
299 vapier 1.76 Elf ## B ## _Rel *rel; \
300     Elf ## B ## _Rela *rela; \
301     /* search the section headers for relocations */ \
302     for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
303     uint32_t sh_type = EGET(shdr[s].sh_type); \
304     if (sh_type == SHT_REL) { \
305     rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
306     rela = NULL; \
307     rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
308     } else if (sh_type == SHT_RELA) { \
309     rel = NULL; \
310     rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
311     rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
312     } else \
313     continue; \
314 vapier 1.82 /* now see if any of the relocs are in the .text */ \
315     for (r = 0; r < rmax; ++r) { \
316     unsigned long sym_max; \
317     Elf ## B ## _Addr offset_tmp; \
318     Elf ## B ## _Sym *func; \
319     Elf ## B ## _Sym *sym; \
320     Elf ## B ## _Addr r_offset; \
321     uint ## B ## _t r_info; \
322     if (sh_type == SHT_REL) { \
323     r_offset = EGET(rel[r].r_offset); \
324     r_info = EGET(rel[r].r_info); \
325     } else { \
326     r_offset = EGET(rela[r].r_offset); \
327     r_info = EGET(rela[r].r_info); \
328     } \
329     /* make sure this relocation is inside of the .text */ \
330     if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
331     if (be_verbose <= 2) continue; \
332     } else \
333 vapier 1.78 *found_textrels = 1; \
334 vapier 1.82 /* locate this relocation symbol name */ \
335     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
336 vapier 1.112 if ((void*)sym > (void*)elf->data_end) { \
337 vapier 1.111 warn("%s: corrupt ELF symbol", elf->filename); \
338 vapier 1.109 continue; \
339     } \
340 vapier 1.82 sym_max = ELF ## B ## _R_SYM(r_info); \
341     if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
342     sym += sym_max; \
343     else \
344     sym = NULL; \
345     sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
346     /* show the raw details about this reloc */ \
347 vapier 1.88 printf(" %s: ", elf->base_filename); \
348 vapier 1.82 if (sym && sym->st_name) \
349     printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
350     else \
351 vapier 1.88 printf("(memory/fake?)"); \
352 vapier 1.82 printf(" [0x%lX]", (unsigned long)r_offset); \
353     /* now try to find the closest symbol that this rel is probably in */ \
354     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
355     func = NULL; \
356     offset_tmp = 0; \
357     while (sym_max--) { \
358     if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
359     func = sym; \
360     offset_tmp = EGET(sym->st_value); \
361 vapier 1.76 } \
362 vapier 1.82 ++sym; \
363 vapier 1.76 } \
364 vapier 1.82 printf(" in "); \
365     if (func && func->st_name) \
366     printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
367     else \
368     printf("(NULL: fake?)"); \
369     printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
370 vapier 1.76 } \
371     } }
372     SHOW_TEXTRELS(32)
373     SHOW_TEXTRELS(64)
374     }
375 vapier 1.82 if (!*found_textrels)
376     warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
377 vapier 1.76
378     return NULL;
379     }
380 solar 1.83
381 vapier 1.102 static void rpath_security_checks(elfobj *, char *, const char *);
382     static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
383 vapier 1.100 {
384 solar 1.83 struct stat st;
385 vapier 1.84 switch (*item) {
386 vapier 1.89 case '/': break;
387     case '.':
388 vapier 1.102 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
389 vapier 1.89 break;
390 vapier 1.100 case ':':
391 vapier 1.89 case '\0':
392 vapier 1.102 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
393 solar 1.83 break;
394     case '$':
395 vapier 1.84 if (fstat(elf->fd, &st) != -1)
396 solar 1.83 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
397 vapier 1.102 warnf("Security problem with %s='%s' in %s with mode set of %o",
398     dt_type, item, elf->filename, st.st_mode & 07777);
399 solar 1.83 break;
400     default:
401 vapier 1.102 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
402 solar 1.83 break;
403     }
404     }
405 vapier 1.41 static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
406 vapier 1.39 {
407 vapier 1.48 unsigned long i, s;
408     char *rpath, *runpath, **r;
409 vapier 1.39 void *strtbl_void;
410 vapier 1.10
411 vapier 1.39 if (!show_rpath) return;
412 vapier 1.10
413 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
414     rpath = runpath = NULL;
415 vapier 1.10
416 vapier 1.44 if (elf->phdr && strtbl_void) {
417 vapier 1.26 #define SHOW_RPATH(B) \
418     if (elf->elf_class == ELFCLASS ## B) { \
419     Elf ## B ## _Dyn *dyn; \
420     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
421     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
422     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
423 vapier 1.44 Elf ## B ## _Off offset; \
424 vapier 1.60 Elf ## B ## _Xword word; \
425 vapier 1.48 /* Scan all the program headers */ \
426 vapier 1.26 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
427 vapier 1.48 /* Just scan dynamic headers */ \
428 vapier 1.26 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
429 vapier 1.44 offset = EGET(phdr[i].p_offset); \
430     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
431 vapier 1.48 /* Just scan dynamic RPATH/RUNPATH headers */ \
432 vapier 1.44 dyn = DYN ## B (elf->data + offset); \
433 vapier 1.48 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
434     if (word == DT_RPATH) { \
435     r = &rpath; \
436     } else if (word == DT_RUNPATH) { \
437     r = &runpath; \
438     } else { \
439     ++dyn; \
440     continue; \
441     } \
442     /* Verify the memory is somewhat sane */ \
443     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
444 vapier 1.69 if (offset < (Elf ## B ## _Off)elf->len) { \
445 vapier 1.48 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
446     *r = (char*)(elf->data + offset); \
447 vapier 1.103 /* cache the length in case we need to nuke this section later on */ \
448     if (fix_elf) \
449     offset = strlen(*r); \
450 vapier 1.48 /* If quiet, don't output paths in ld.so.conf */ \
451 vapier 1.69 if (be_quiet) { \
452     size_t len; \
453     char *start, *end; \
454 vapier 1.75 /* note that we only 'chop' off leading known paths. */ \
455     /* since *r is read-only memory, we can only move the ptr forward. */ \
456     start = *r; \
457     /* scan each path in : delimited list */ \
458     while (start) { \
459 vapier 1.102 rpath_security_checks(elf, start, get_elfdtype(word)); \
460 vapier 1.69 end = strchr(start, ':'); \
461 vapier 1.75 len = (end ? abs(end - start) : strlen(start)); \
462 vapier 1.102 if (use_ldcache) \
463     for (s = 0; ldpaths[s]; ++s) \
464     if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
465     *r = end; \
466     /* corner case ... if RPATH reads "/usr/lib:", we want \
467     * to show ':' rather than '' */ \
468     if (end && end[1] != '\0') \
469     (*r)++; \
470     break; \
471     } \
472 vapier 1.100 if (!*r || !end) \
473     break; \
474 vapier 1.75 else \
475     start = start + len + 1; \
476 vapier 1.69 } \
477     } \
478 vapier 1.101 if (*r) { \
479 solar 1.107 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
480 vapier 1.101 /* just nuke it */ \
481     nuke_it##B: \
482 vapier 1.103 memset(*r, 0x00, offset); \
483 vapier 1.102 *r = NULL; \
484 vapier 1.101 ESET(dyn->d_tag, DT_DEBUG); \
485 vapier 1.103 ESET(dyn->d_un.d_ptr, 0); \
486 vapier 1.101 } else if (fix_elf) { \
487     /* try to clean "bad" paths */ \
488     size_t len, tmpdir_len; \
489     char *start, *end; \
490     const char *tmpdir; \
491     start = *r; \
492     tmpdir = (getenv("TMPDIR") ? : "."); \
493     tmpdir_len = strlen(tmpdir); \
494     while (1) { \
495     end = strchr(start, ':'); \
496     if (start == end) { \
497     eat_this_path##B: \
498     len = strlen(end); \
499     memmove(start, end+1, len); \
500     start[len-1] = '\0'; \
501     end = start - 1; \
502     } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
503     if (!end) { \
504     if (start == *r) \
505     goto nuke_it##B; \
506     *--start = '\0'; \
507     } else \
508     goto eat_this_path##B; \
509     } \
510     if (!end) \
511     break; \
512     start = end + 1; \
513     } \
514 vapier 1.102 if (**r == '\0') \
515     goto nuke_it##B; \
516 vapier 1.101 } \
517 vapier 1.102 if (*r) \
518     *found_rpath = 1; \
519 vapier 1.101 } \
520 vapier 1.26 } \
521     ++dyn; \
522     } \
523     } }
524     SHOW_RPATH(32)
525     SHOW_RPATH(64)
526 vapier 1.10 }
527 vapier 1.41
528 vapier 1.70 if (be_wewy_wewy_quiet) return;
529    
530 vapier 1.39 if (rpath && runpath) {
531 vapier 1.41 if (!strcmp(rpath, runpath)) {
532     xstrcat(ret, runpath, ret_len);
533     } else {
534 vapier 1.39 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
535 vapier 1.41 xchrcat(ret, '{', ret_len);
536     xstrcat(ret, rpath, ret_len);
537     xchrcat(ret, ',', ret_len);
538     xstrcat(ret, runpath, ret_len);
539     xchrcat(ret, '}', ret_len);
540 vapier 1.39 }
541     } else if (rpath || runpath)
542 vapier 1.41 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
543     else if (!be_quiet)
544     xstrcat(ret, " - ", ret_len);
545 vapier 1.39 }
546 solar 1.96
547     #define LDSO_CACHE_MAGIC "ld.so-"
548     #define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
549     #define LDSO_CACHE_VER "1.7.0"
550     #define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
551 vapier 1.97 #define FLAG_ANY -1
552     #define FLAG_TYPE_MASK 0x00ff
553     #define FLAG_LIBC4 0x0000
554     #define FLAG_ELF 0x0001
555     #define FLAG_ELF_LIBC5 0x0002
556     #define FLAG_ELF_LIBC6 0x0003
557     #define FLAG_REQUIRED_MASK 0xff00
558     #define FLAG_SPARC_LIB64 0x0100
559     #define FLAG_IA64_LIB64 0x0200
560     #define FLAG_X8664_LIB64 0x0300
561     #define FLAG_S390_LIB64 0x0400
562     #define FLAG_POWERPC_LIB64 0x0500
563     #define FLAG_MIPS64_LIBN32 0x0600
564     #define FLAG_MIPS64_LIBN64 0x0700
565 solar 1.96
566 vapier 1.97 static char *lookup_cache_lib(elfobj *, char *);
567     static char *lookup_cache_lib(elfobj *elf, char *fname)
568 solar 1.96 {
569     int fd = 0;
570     char *strs;
571 vapier 1.104 static char buf[__PAX_UTILS_PATH_MAX] = "";
572 solar 1.96 const char *cachefile = "/etc/ld.so.cache";
573     struct stat st;
574    
575     typedef struct {
576     char magic[LDSO_CACHE_MAGIC_LEN];
577     char version[LDSO_CACHE_VER_LEN];
578     int nlibs;
579     } header_t;
580 vapier 1.97 header_t *header;
581 solar 1.96
582     typedef struct {
583     int flags;
584     int sooffset;
585     int liboffset;
586     } libentry_t;
587     libentry_t *libent;
588    
589     if (fname == NULL)
590     return NULL;
591    
592     if (ldcache == 0) {
593 vapier 1.97 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
594 solar 1.96 return NULL;
595 vapier 1.97
596     /* cache these values so we only map/unmap the cache file once */
597 solar 1.96 ldcache_size = st.st_size;
598 vapier 1.97 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
599    
600     close(fd);
601 solar 1.96
602 solar 1.116 if (ldcache == (caddr_t)-1) {
603     ldcache = 0;
604 solar 1.96 return NULL;
605 solar 1.116 }
606 solar 1.96
607     if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
608     return NULL;
609     if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
610     return NULL;
611     }
612    
613     header = (header_t *) ldcache;
614     libent = (libentry_t *) (ldcache + sizeof(header_t));
615     strs = (char *) &libent[header->nlibs];
616    
617     for (fd = 0; fd < header->nlibs; fd++) {
618 vapier 1.97 /* this should be more fine grained, but for now we assume that
619     * diff arches will not be cached together. and we ignore the
620     * the different multilib mips cases. */
621     if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
622     continue;
623     if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
624     continue;
625    
626 solar 1.96 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
627     continue;
628     strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
629     }
630     return buf;
631     }
632    
633    
634 vapier 1.84 static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
635 vapier 1.39 {
636 vapier 1.44 unsigned long i;
637 vapier 1.39 char *needed;
638     void *strtbl_void;
639 solar 1.96 char *p;
640 vapier 1.39
641 vapier 1.72 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
642 vapier 1.10
643 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
644 vapier 1.32
645 vapier 1.44 if (elf->phdr && strtbl_void) {
646 vapier 1.32 #define SHOW_NEEDED(B) \
647     if (elf->elf_class == ELFCLASS ## B) { \
648     Elf ## B ## _Dyn *dyn; \
649     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
650     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
651     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
652 vapier 1.44 Elf ## B ## _Off offset; \
653 vapier 1.32 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
654     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
655 vapier 1.44 offset = EGET(phdr[i].p_offset); \
656     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
657     dyn = DYN ## B (elf->data + offset); \
658 vapier 1.32 while (EGET(dyn->d_tag) != DT_NULL) { \
659     if (EGET(dyn->d_tag) == DT_NEEDED) { \
660 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
661 vapier 1.69 if (offset >= (Elf ## B ## _Off)elf->len) { \
662 vapier 1.49 ++dyn; \
663     continue; \
664     } \
665 vapier 1.44 needed = (char*)(elf->data + offset); \
666 vapier 1.72 if (op == 0) { \
667     if (!be_wewy_wewy_quiet) { \
668     if (*found_needed) xchrcat(ret, ',', ret_len); \
669 vapier 1.102 if (use_ldcache) \
670 vapier 1.97 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
671 solar 1.96 needed = p; \
672 vapier 1.72 xstrcat(ret, needed, ret_len); \
673     } \
674     *found_needed = 1; \
675     } else { \
676 solar 1.86 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
677 vapier 1.81 *found_lib = 1; \
678 solar 1.86 return (be_wewy_wewy_quiet ? NULL : needed); \
679 vapier 1.81 } \
680 vapier 1.72 } \
681 vapier 1.32 } \
682     ++dyn; \
683     } \
684     } }
685     SHOW_NEEDED(32)
686     SHOW_NEEDED(64)
687 vapier 1.85 if (op == 0 && !*found_needed && be_verbose)
688 vapier 1.84 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
689 vapier 1.32 }
690 vapier 1.72
691     return NULL;
692 vapier 1.39 }
693 vapier 1.41 static char *scanelf_file_interp(elfobj *elf, char *found_interp)
694 vapier 1.39 {
695     void *strtbl_void;
696    
697 vapier 1.41 if (!show_interp) return NULL;
698 vapier 1.32
699 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".interp");
700 vapier 1.38
701 vapier 1.39 if (strtbl_void) {
702 vapier 1.38 #define SHOW_INTERP(B) \
703     if (elf->elf_class == ELFCLASS ## B) { \
704 solar 1.40 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
705     *found_interp = 1; \
706 vapier 1.70 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
707 vapier 1.38 }
708     SHOW_INTERP(32)
709     SHOW_INTERP(64)
710     }
711 vapier 1.41 return NULL;
712 vapier 1.39 }
713 vapier 1.49 static char *scanelf_file_bind(elfobj *elf, char *found_bind)
714     {
715     unsigned long i;
716     struct stat s;
717    
718     if (!show_bind) return NULL;
719 vapier 1.51 if (!elf->phdr) return NULL;
720 vapier 1.49
721     #define SHOW_BIND(B) \
722     if (elf->elf_class == ELFCLASS ## B) { \
723     Elf ## B ## _Dyn *dyn; \
724     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
725     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
726     Elf ## B ## _Off offset; \
727     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
728     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
729     offset = EGET(phdr[i].p_offset); \
730     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
731     dyn = DYN ## B (elf->data + offset); \
732     while (EGET(dyn->d_tag) != DT_NULL) { \
733     if (EGET(dyn->d_tag) == DT_BIND_NOW || \
734     (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
735     { \
736     if (be_quiet) return NULL; \
737     *found_bind = 1; \
738 vapier 1.70 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
739 vapier 1.49 } \
740     ++dyn; \
741     } \
742     } \
743     }
744     SHOW_BIND(32)
745     SHOW_BIND(64)
746    
747 vapier 1.70 if (be_wewy_wewy_quiet) return NULL;
748    
749 vapier 1.56 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
750 vapier 1.49 return NULL;
751     } else {
752     *found_bind = 1;
753 solar 1.68 return (char *) "LAZY";
754 vapier 1.49 }
755     }
756 vapier 1.84 static char *scanelf_file_soname(elfobj *elf, char *found_soname)
757     {
758     unsigned long i;
759     char *soname;
760     void *strtbl_void;
761    
762     if (!show_soname) return NULL;
763    
764     strtbl_void = elf_findsecbyname(elf, ".dynstr");
765    
766     if (elf->phdr && strtbl_void) {
767     #define SHOW_SONAME(B) \
768     if (elf->elf_class == ELFCLASS ## B) { \
769     Elf ## B ## _Dyn *dyn; \
770     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
771     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
772     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
773     Elf ## B ## _Off offset; \
774     /* only look for soname in shared objects */ \
775     if (ehdr->e_type != ET_DYN) \
776     return NULL; \
777     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
778     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
779     offset = EGET(phdr[i].p_offset); \
780     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
781     dyn = DYN ## B (elf->data + offset); \
782     while (EGET(dyn->d_tag) != DT_NULL) { \
783     if (EGET(dyn->d_tag) == DT_SONAME) { \
784     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
785     if (offset >= (Elf ## B ## _Off)elf->len) { \
786     ++dyn; \
787     continue; \
788     } \
789     soname = (char*)(elf->data + offset); \
790     *found_soname = 1; \
791     return (be_wewy_wewy_quiet ? NULL : soname); \
792     } \
793     ++dyn; \
794     } \
795     } }
796     SHOW_SONAME(32)
797     SHOW_SONAME(64)
798     }
799    
800     return NULL;
801     }
802 vapier 1.72 static char *scanelf_file_sym(elfobj *elf, char *found_sym)
803 vapier 1.39 {
804 vapier 1.44 unsigned long i;
805 vapier 1.95 char *ret;
806 vapier 1.39 void *symtab_void, *strtab_void;
807 vapier 1.38
808 vapier 1.41 if (!find_sym) return NULL;
809 vapier 1.95 ret = find_sym;
810 vapier 1.32
811 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
812 vapier 1.27
813 vapier 1.39 if (symtab_void && strtab_void) {
814 vapier 1.27 #define FIND_SYM(B) \
815     if (elf->elf_class == ELFCLASS ## B) { \
816     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
817     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
818     Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
819 vapier 1.115 unsigned long cnt = EGET(symtab->sh_entsize); \
820 vapier 1.27 char *symname; \
821 vapier 1.115 if (cnt) \
822     cnt = EGET(symtab->sh_size) / cnt; \
823 vapier 1.27 for (i = 0; i < cnt; ++i) { \
824     if (sym->st_name) { \
825     symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
826 vapier 1.115 if ((void*)symname > (void*)elf->data_end) { \
827     warnf("%s: corrupt ELF symbols", elf->filename); \
828 vapier 1.111 continue; \
829     } \
830 solar 1.28 if (*find_sym == '*') { \
831 vapier 1.32 printf("%s(%s) %5lX %15s %s\n", \
832 vapier 1.39 ((*found_sym == 0) ? "\n\t" : "\t"), \
833 vapier 1.76 elf->base_filename, \
834 vapier 1.94 (unsigned long)sym->st_size, \
835 vapier 1.95 get_elfstttype(sym->st_info), \
836 vapier 1.32 symname); \
837 vapier 1.39 *found_sym = 1; \
838 vapier 1.95 } else { \
839     char *this_sym, *next_sym; \
840     this_sym = find_sym; \
841     do { \
842     next_sym = strchr(this_sym, ','); \
843     if (next_sym == NULL) \
844     next_sym = this_sym + strlen(this_sym); \
845     if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
846     (strcmp(symname, versioned_symname) == 0)) { \
847     ret = this_sym; \
848     (*found_sym)++; \
849     goto break_out; \
850     } \
851     this_sym = next_sym + 1; \
852     } while (*next_sym != '\0'); \
853     } \
854 vapier 1.27 } \
855     ++sym; \
856     } }
857     FIND_SYM(32)
858     FIND_SYM(64)
859 vapier 1.39 }
860 vapier 1.70
861 vapier 1.95 break_out:
862 vapier 1.70 if (be_wewy_wewy_quiet) return NULL;
863    
864 vapier 1.41 if (*find_sym != '*' && *found_sym)
865 vapier 1.95 return ret;
866 vapier 1.41 if (be_quiet)
867     return NULL;
868     else
869 solar 1.68 return (char *)" - ";
870 vapier 1.39 }
871     /* scan an elf file and show all the fun stuff */
872 solar 1.57 #define prints(str) write(fileno(stdout), str, strlen(str))
873 vapier 1.106 static int scanelf_elfobj(elfobj *elf)
874 vapier 1.39 {
875 vapier 1.44 unsigned long i;
876 solar 1.73 char found_pax, found_phdr, found_relro, found_load, found_textrel,
877 vapier 1.84 found_rpath, found_needed, found_interp, found_bind, found_soname,
878 vapier 1.76 found_sym, found_lib, found_file, found_textrels;
879 vapier 1.41 static char *out_buffer = NULL;
880     static size_t out_len;
881 vapier 1.39
882 vapier 1.76 found_pax = found_phdr = found_relro = found_load = found_textrel = \
883 vapier 1.84 found_rpath = found_needed = found_interp = found_bind = found_soname = \
884 vapier 1.76 found_sym = found_lib = found_file = found_textrels = 0;
885 vapier 1.39
886 vapier 1.114 if (be_verbose > 2)
887 vapier 1.106 printf("%s: scanning file {%s,%s}\n", elf->filename,
888 vapier 1.69 get_elfeitype(EI_CLASS, elf->elf_class),
889     get_elfeitype(EI_DATA, elf->data[EI_DATA]));
890 vapier 1.114 else if (be_verbose > 1)
891 vapier 1.106 printf("%s: scanning file\n", elf->filename);
892 vapier 1.39
893 vapier 1.41 /* init output buffer */
894     if (!out_buffer) {
895     out_len = sizeof(char) * 80;
896     out_buffer = (char*)xmalloc(out_len);
897     }
898     *out_buffer = '\0';
899    
900 vapier 1.39 /* show the header */
901     if (!be_quiet && show_banner) {
902 vapier 1.49 for (i = 0; out_format[i]; ++i) {
903 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
904 vapier 1.41
905     switch (out_format[++i]) {
906     case '%': break;
907 vapier 1.70 case '#': break;
908 vapier 1.66 case 'F':
909     case 'p':
910     case 'f': prints("FILE "); found_file = 1; break;
911 vapier 1.41 case 'o': prints(" TYPE "); break;
912     case 'x': prints(" PAX "); break;
913 vapier 1.71 case 'e': prints("STK/REL/PTL "); break;
914 vapier 1.41 case 't': prints("TEXTREL "); break;
915     case 'r': prints("RPATH "); break;
916     case 'n': prints("NEEDED "); break;
917     case 'i': prints("INTERP "); break;
918 vapier 1.49 case 'b': prints("BIND "); break;
919 vapier 1.84 case 'S': prints("SONAME "); break;
920 vapier 1.41 case 's': prints("SYM "); break;
921 vapier 1.72 case 'N': prints("LIB "); break;
922 vapier 1.76 case 'T': prints("TEXTRELS "); break;
923     default: warnf("'%c' has no title ?", out_format[i]);
924 vapier 1.39 }
925 vapier 1.27 }
926 vapier 1.49 if (!found_file) prints("FILE ");
927 vapier 1.41 prints("\n");
928 vapier 1.49 found_file = 0;
929 vapier 1.39 show_banner = 0;
930     }
931    
932     /* dump all the good stuff */
933 vapier 1.49 for (i = 0; out_format[i]; ++i) {
934 vapier 1.41 const char *out;
935 vapier 1.66 const char *tmp;
936 vapier 1.41
937     /* make sure we trim leading spaces in quiet mode */
938     if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
939     *out_buffer = '\0';
940 vapier 1.39
941 vapier 1.70 if (!IS_MODIFIER(out_format[i])) {
942 vapier 1.41 xchrcat(&out_buffer, out_format[i], &out_len);
943     continue;
944     }
945 vapier 1.39
946 vapier 1.41 out = NULL;
947 vapier 1.70 be_wewy_wewy_quiet = (out_format[i] == '#');
948 vapier 1.41 switch (out_format[++i]) {
949 vapier 1.70 case '%':
950     case '#':
951     xchrcat(&out_buffer, out_format[i], &out_len); break;
952     case 'F':
953 vapier 1.76 found_file = 1;
954 vapier 1.70 if (be_wewy_wewy_quiet) break;
955 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
956 vapier 1.70 break;
957 vapier 1.66 case 'p':
958 vapier 1.76 found_file = 1;
959 vapier 1.70 if (be_wewy_wewy_quiet) break;
960 vapier 1.106 tmp = elf->filename;
961 vapier 1.66 if (search_path) {
962     ssize_t len_search = strlen(search_path);
963 vapier 1.106 ssize_t len_file = strlen(elf->filename);
964     if (!strncmp(elf->filename, search_path, len_search) && \
965 vapier 1.66 len_file > len_search)
966     tmp += len_search;
967     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
968     }
969     xstrcat(&out_buffer, tmp, &out_len);
970     break;
971     case 'f':
972 vapier 1.76 found_file = 1;
973 vapier 1.70 if (be_wewy_wewy_quiet) break;
974 vapier 1.106 tmp = strrchr(elf->filename, '/');
975     tmp = (tmp == NULL ? elf->filename : tmp+1);
976 vapier 1.66 xstrcat(&out_buffer, tmp, &out_len);
977     break;
978 vapier 1.41 case 'o': out = get_elfetype(elf); break;
979     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
980 solar 1.73 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
981 vapier 1.41 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
982 vapier 1.79 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
983 vapier 1.41 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
984 vapier 1.72 case 'n':
985     case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
986 vapier 1.41 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
987 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
988 vapier 1.84 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
989 vapier 1.72 case 's': out = scanelf_file_sym(elf, &found_sym); break;
990 vapier 1.76 default: warnf("'%c' has no scan code?", out_format[i]);
991 vapier 1.29 }
992 vapier 1.95 if (out) {
993     /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
994     if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
995     xstrncat(&out_buffer, out, &out_len, (tmp-out));
996     else
997     xstrcat(&out_buffer, out, &out_len);
998     }
999 vapier 1.39 }
1000    
1001 vapier 1.54 #define FOUND_SOMETHING() \
1002 solar 1.73 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1003 vapier 1.76 found_rpath || found_needed || found_interp || found_bind || \
1004 vapier 1.84 found_soname || found_sym || found_lib || found_textrels)
1005 vapier 1.54
1006     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1007     xchrcat(&out_buffer, ' ', &out_len);
1008 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1009 vapier 1.27 }
1010 vapier 1.79 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1011 vapier 1.41 puts(out_buffer);
1012 vapier 1.79 fflush(stdout);
1013     }
1014 vapier 1.10
1015 vapier 1.105 return 0;
1016     }
1017    
1018 vapier 1.106 /* scan a single elf */
1019     static int scanelf_elf(const char *filename, int fd, size_t len)
1020     {
1021     int ret;
1022     elfobj *elf;
1023    
1024     /* verify this is real ELF */
1025     if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1026     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1027     return 1;
1028     }
1029    
1030     ret = scanelf_elfobj(elf);
1031     unreadelf(elf);
1032     return ret;
1033     }
1034 vapier 1.105 /* scan an archive of elfs */
1035 vapier 1.106 static int scanelf_archive(const char *filename, int fd, size_t len)
1036 vapier 1.105 {
1037 vapier 1.106 archive_handle *ar;
1038 vapier 1.105 archive_member *m;
1039 vapier 1.106 char *ar_buffer;
1040     elfobj *elf;
1041    
1042     ar = ar_open_fd(filename, fd);
1043     if (ar == NULL)
1044     return 1;
1045    
1046     ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1047     while ((m=ar_next(ar)) != NULL) {
1048     elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1049     if (elf) {
1050     scanelf_elfobj(elf);
1051     unreadelf(elf);
1052     }
1053     }
1054     munmap(ar_buffer, len);
1055    
1056 vapier 1.105 return 0;
1057     }
1058     /* scan a file which may be an elf or an archive or some other magical beast */
1059     static void scanelf_file(const char *filename)
1060     {
1061     struct stat st;
1062 vapier 1.106 int fd;
1063 vapier 1.105
1064     /* make sure 'filename' exists */
1065     if (lstat(filename, &st) == -1) {
1066     if (be_verbose > 2) printf("%s: does not exist\n", filename);
1067     return;
1068     }
1069    
1070     /* always handle regular files and handle symlinked files if no -y */
1071     if (S_ISLNK(st.st_mode)) {
1072     if (!scan_symlink) return;
1073     stat(filename, &st);
1074     }
1075     if (!S_ISREG(st.st_mode)) {
1076     if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1077     return;
1078     }
1079    
1080 vapier 1.106 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1081     return;
1082    
1083     if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives)
1084 vapier 1.105 /* if it isn't an ELF, maybe it's an .a archive */
1085 vapier 1.106 scanelf_archive(filename, fd, st.st_size);
1086    
1087     close(fd);
1088 solar 1.6 }
1089    
1090 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
1091 vapier 1.10 static void scanelf_dir(const char *path)
1092 solar 1.1 {
1093 vapier 1.10 register DIR *dir;
1094     register struct dirent *dentry;
1095 vapier 1.14 struct stat st_top, st;
1096 vapier 1.104 char buf[__PAX_UTILS_PATH_MAX];
1097 vapier 1.32 size_t pathlen = 0, len = 0;
1098 vapier 1.10
1099     /* make sure path exists */
1100 vapier 1.39 if (lstat(path, &st_top) == -1) {
1101     if (be_verbose > 2) printf("%s: does not exist\n", path);
1102 vapier 1.10 return;
1103 vapier 1.39 }
1104 solar 1.11
1105 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
1106 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
1107 vapier 1.10 scanelf_file(path);
1108     return;
1109     }
1110    
1111     /* now scan the dir looking for fun stuff */
1112     if ((dir = opendir(path)) == NULL) {
1113     warnf("could not opendir %s: %s", path, strerror(errno));
1114     return;
1115     }
1116 vapier 1.114 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1117 solar 1.11
1118 vapier 1.32 pathlen = strlen(path);
1119 vapier 1.10 while ((dentry = readdir(dir))) {
1120     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1121     continue;
1122 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
1123     if (len >= sizeof(buf)) {
1124 vapier 1.76 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1125     (unsigned long)len, (unsigned long)sizeof(buf));
1126 vapier 1.32 continue;
1127     }
1128 solar 1.31 sprintf(buf, "%s/%s", path, dentry->d_name);
1129 solar 1.20 if (lstat(buf, &st) != -1) {
1130 vapier 1.10 if (S_ISREG(st.st_mode))
1131 solar 1.20 scanelf_file(buf);
1132 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1133 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1134 solar 1.20 scanelf_dir(buf);
1135 vapier 1.10 }
1136     }
1137     }
1138     closedir(dir);
1139 solar 1.1 }
1140    
1141 vapier 1.47 static int scanelf_from_file(char *filename)
1142     {
1143 solar 1.45 FILE *fp = NULL;
1144     char *p;
1145 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1146 solar 1.45
1147     if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
1148     fp = stdin;
1149     else if ((fp = fopen(filename, "r")) == NULL)
1150     return 1;
1151    
1152 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1153 solar 1.45 if ((p = strchr(path, '\n')) != NULL)
1154     *p = 0;
1155 vapier 1.66 search_path = path;
1156 solar 1.45 scanelf_dir(path);
1157     }
1158     if (fp != stdin)
1159     fclose(fp);
1160     return 0;
1161     }
1162    
1163 vapier 1.48 static void load_ld_so_conf()
1164     {
1165     FILE *fp = NULL;
1166     char *p;
1167 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1168 vapier 1.48 int i = 0;
1169    
1170     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
1171     return;
1172    
1173 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1174 vapier 1.48 if (*path != '/')
1175     continue;
1176    
1177     if ((p = strrchr(path, '\r')) != NULL)
1178     *p = 0;
1179     if ((p = strchr(path, '\n')) != NULL)
1180     *p = 0;
1181    
1182     ldpaths[i++] = xstrdup(path);
1183    
1184     if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1185     break;
1186     }
1187     ldpaths[i] = NULL;
1188    
1189     fclose(fp);
1190     }
1191    
1192 vapier 1.10 /* scan /etc/ld.so.conf for paths */
1193     static void scanelf_ldpath()
1194     {
1195 vapier 1.17 char scan_l, scan_ul, scan_ull;
1196 vapier 1.48 int i = 0;
1197 vapier 1.10
1198 vapier 1.48 if (!ldpaths[0])
1199     err("Unable to load any paths from ld.so.conf");
1200 vapier 1.10
1201 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
1202    
1203 vapier 1.48 while (ldpaths[i]) {
1204     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
1205     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
1206     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
1207     scanelf_dir(ldpaths[i]);
1208     ++i;
1209     }
1210 vapier 1.10
1211 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
1212     if (!scan_ul) scanelf_dir("/usr/lib");
1213     if (!scan_ull) scanelf_dir("/usr/local/lib");
1214 vapier 1.10 }
1215 solar 1.1
1216 vapier 1.10 /* scan env PATH for paths */
1217     static void scanelf_envpath()
1218 solar 1.1 {
1219 solar 1.34 char *path, *p;
1220 vapier 1.10
1221     path = getenv("PATH");
1222     if (!path)
1223     err("PATH is not set in your env !");
1224 vapier 1.41 path = xstrdup(path);
1225 vapier 1.10
1226     while ((p = strrchr(path, ':')) != NULL) {
1227     scanelf_dir(p + 1);
1228     *p = 0;
1229     }
1230 vapier 1.17
1231 solar 1.34 free(path);
1232 solar 1.1 }
1233    
1234    
1235 vapier 1.10 /* usage / invocation handling functions */
1236 vapier 1.105 #define PARSE_FLAGS "plRmyAXxetrnLibSs:gN:TaqvF:f:o:BhV"
1237 vapier 1.27 #define a_argument required_argument
1238 vapier 1.10 static struct option const long_opts[] = {
1239     {"path", no_argument, NULL, 'p'},
1240     {"ldpath", no_argument, NULL, 'l'},
1241     {"recursive", no_argument, NULL, 'R'},
1242 vapier 1.14 {"mount", no_argument, NULL, 'm'},
1243 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
1244 vapier 1.105 {"archives", no_argument, NULL, 'A'},
1245     {"ldcache", no_argument, NULL, 'L'},
1246 vapier 1.101 {"fix", no_argument, NULL, 'X'},
1247 vapier 1.10 {"pax", no_argument, NULL, 'x'},
1248 solar 1.16 {"header", no_argument, NULL, 'e'},
1249 vapier 1.10 {"textrel", no_argument, NULL, 't'},
1250     {"rpath", no_argument, NULL, 'r'},
1251 vapier 1.32 {"needed", no_argument, NULL, 'n'},
1252 vapier 1.38 {"interp", no_argument, NULL, 'i'},
1253 vapier 1.49 {"bind", no_argument, NULL, 'b'},
1254 vapier 1.84 {"soname", no_argument, NULL, 'S'},
1255 vapier 1.76 {"symbol", a_argument, NULL, 's'},
1256     {"lib", a_argument, NULL, 'N'},
1257 solar 1.86 {"gmatch", no_argument, NULL, 'g'},
1258 vapier 1.76 {"textrels", no_argument, NULL, 'T'},
1259 vapier 1.10 {"all", no_argument, NULL, 'a'},
1260     {"quiet", no_argument, NULL, 'q'},
1261 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
1262 vapier 1.76 {"format", a_argument, NULL, 'F'},
1263     {"from", a_argument, NULL, 'f'},
1264     {"file", a_argument, NULL, 'o'},
1265 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
1266 vapier 1.10 {"help", no_argument, NULL, 'h'},
1267     {"version", no_argument, NULL, 'V'},
1268     {NULL, no_argument, NULL, 0x0}
1269     };
1270 solar 1.57
1271 solar 1.68 static const char *opts_help[] = {
1272 vapier 1.10 "Scan all directories in PATH environment",
1273     "Scan all directories in /etc/ld.so.conf",
1274 vapier 1.14 "Scan directories recursively",
1275 vapier 1.37 "Don't recursively cross mount points",
1276 vapier 1.101 "Don't scan symlinks",
1277 vapier 1.105 "Scan archives (.a files)",
1278     "Utilize ld.so.cache information (use with -r/-n)",
1279 vapier 1.101 "Try and 'fix' bad things (use with -r/-e)\n",
1280 vapier 1.10 "Print PaX markings",
1281 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
1282 vapier 1.10 "Print TEXTREL information",
1283     "Print RPATH information",
1284 vapier 1.32 "Print NEEDED information",
1285 vapier 1.38 "Print INTERP information",
1286 vapier 1.49 "Print BIND information",
1287 vapier 1.84 "Print SONAME information",
1288 vapier 1.27 "Find a specified symbol",
1289 vapier 1.72 "Find a specified library",
1290 solar 1.86 "Use strncmp to match libraries. (use with -N)",
1291 vapier 1.76 "Locate cause of TEXTREL",
1292 vapier 1.82 "Print all scanned info (-x -e -t -r -b)\n",
1293 vapier 1.14 "Only output 'bad' things",
1294     "Be verbose (can be specified more than once)",
1295 vapier 1.39 "Use specified format for output",
1296 solar 1.45 "Read input stream from a filename",
1297 vapier 1.24 "Write output stream to a filename",
1298 vapier 1.14 "Don't display the header",
1299 vapier 1.10 "Print this help and exit",
1300     "Print version and exit",
1301     NULL
1302     };
1303    
1304     /* display usage and exit */
1305     static void usage(int status)
1306 solar 1.1 {
1307 vapier 1.44 unsigned long i;
1308 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
1309 vapier 1.105 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1310 solar 1.35 printf("Options: -[%s]\n", PARSE_FLAGS);
1311 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
1312 vapier 1.27 if (long_opts[i].has_arg == no_argument)
1313 solar 1.52 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
1314 vapier 1.27 long_opts[i].name, opts_help[i]);
1315     else
1316 solar 1.52 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
1317 vapier 1.27 long_opts[i].name, opts_help[i]);
1318 solar 1.45
1319     if (status != EXIT_SUCCESS)
1320     exit(status);
1321    
1322 vapier 1.46 puts("\nThe format modifiers for the -F option are:");
1323 vapier 1.70 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1324     puts(" t TEXTREL \tr RPATH \tn NEEDED");
1325     puts(" i INTERP \tb BIND \ts symbol");
1326 vapier 1.76 puts(" N library \to Type \tT TEXTRELs");
1327 vapier 1.88 puts(" S SONAME");
1328 vapier 1.70 puts(" p filename (with search path removed)");
1329 vapier 1.88 puts(" f filename (short name/basename)");
1330 vapier 1.70 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1331 solar 1.45
1332 vapier 1.10 exit(status);
1333 solar 1.1 }
1334    
1335     /* parse command line arguments and preform needed actions */
1336 vapier 1.10 static void parseargs(int argc, char *argv[])
1337     {
1338 vapier 1.48 int i;
1339 solar 1.45 char *from_file = NULL;
1340 vapier 1.10
1341     opterr = 0;
1342 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1343     switch (i) {
1344 vapier 1.10
1345 vapier 1.39 case 'V':
1346 vapier 1.80 printf("pax-utils-%s: %s compiled %s\n%s\n"
1347     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1348     VERSION, __FILE__, __DATE__, rcsid, argv0);
1349 vapier 1.10 exit(EXIT_SUCCESS);
1350     break;
1351     case 'h': usage(EXIT_SUCCESS); break;
1352 solar 1.45 case 'f':
1353 vapier 1.100 if (from_file) warn("You prob don't want to specify -f twice");
1354     from_file = optarg;
1355 solar 1.45 break;
1356 vapier 1.24 case 'o': {
1357 solar 1.21 FILE *fp = NULL;
1358 solar 1.64 if ((fp = freopen(optarg, "w", stdout)) == NULL)
1359 vapier 1.24 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1360 vapier 1.65 SET_STDOUT(fp);
1361 solar 1.21 break;
1362     }
1363 vapier 1.24
1364 vapier 1.39 case 's': {
1365 vapier 1.93 if (find_sym) warn("You prob don't want to specify -s twice");
1366     find_sym = optarg;
1367     versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1368 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
1369     break;
1370     }
1371 vapier 1.72 case 'N': {
1372 vapier 1.93 if (find_lib) warn("You prob don't want to specify -N twice");
1373     find_lib = optarg;
1374 vapier 1.72 break;
1375     }
1376 vapier 1.39
1377     case 'F': {
1378 vapier 1.93 if (out_format) warn("You prob don't want to specify -F twice");
1379     out_format = optarg;
1380 vapier 1.39 break;
1381     }
1382 vapier 1.27
1383 solar 1.96 case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */
1384 vapier 1.102 case 'L': use_ldcache = 1; break;
1385 vapier 1.37 case 'y': scan_symlink = 0; break;
1386 vapier 1.105 case 'A': scan_archives = 1; break;
1387 solar 1.16 case 'B': show_banner = 0; break;
1388 vapier 1.10 case 'l': scan_ldpath = 1; break;
1389     case 'p': scan_envpath = 1; break;
1390     case 'R': dir_recurse = 1; break;
1391 vapier 1.14 case 'm': dir_crossmount = 0; break;
1392 vapier 1.101 case 'X': ++fix_elf; break;
1393 vapier 1.10 case 'x': show_pax = 1; break;
1394 solar 1.73 case 'e': show_phdr = 1; break;
1395 vapier 1.10 case 't': show_textrel = 1; break;
1396     case 'r': show_rpath = 1; break;
1397 vapier 1.32 case 'n': show_needed = 1; break;
1398 vapier 1.38 case 'i': show_interp = 1; break;
1399 vapier 1.49 case 'b': show_bind = 1; break;
1400 vapier 1.84 case 'S': show_soname = 1; break;
1401 vapier 1.76 case 'T': show_textrels = 1; break;
1402 vapier 1.10 case 'q': be_quiet = 1; break;
1403 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1404 vapier 1.82 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1405 vapier 1.10
1406     case ':':
1407 vapier 1.113 err("Option '%c' is missing parameter", optopt);
1408 vapier 1.10 case '?':
1409 vapier 1.113 err("Unknown option '%c'", optopt);
1410 vapier 1.10 default:
1411 vapier 1.113 err("Unhandled option '%c'; please report this", i);
1412 vapier 1.10 }
1413     }
1414    
1415 vapier 1.39 /* let the format option override all other options */
1416     if (out_format) {
1417 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1418 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
1419     show_textrels = 0;
1420 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1421 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1422 vapier 1.39
1423 vapier 1.48 switch (out_format[++i]) {
1424 vapier 1.39 case '%': break;
1425 vapier 1.70 case '#': break;
1426 vapier 1.39 case 'F': break;
1427 vapier 1.66 case 'p': break;
1428     case 'f': break;
1429 vapier 1.39 case 's': break;
1430 vapier 1.72 case 'N': break;
1431 vapier 1.41 case 'o': break;
1432 vapier 1.39 case 'x': show_pax = 1; break;
1433 solar 1.73 case 'e': show_phdr = 1; break;
1434 vapier 1.39 case 't': show_textrel = 1; break;
1435     case 'r': show_rpath = 1; break;
1436     case 'n': show_needed = 1; break;
1437     case 'i': show_interp = 1; break;
1438 vapier 1.49 case 'b': show_bind = 1; break;
1439 vapier 1.84 case 'S': show_soname = 1; break;
1440 vapier 1.76 case 'T': show_textrels = 1; break;
1441 vapier 1.39 default:
1442     err("Invalid format specifier '%c' (byte %i)",
1443 vapier 1.48 out_format[i], i+1);
1444 vapier 1.39 }
1445     }
1446 vapier 1.41
1447     /* construct our default format */
1448     } else {
1449     size_t fmt_len = 30;
1450     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1451 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1452     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1453     if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1454     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1455     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1456     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1457     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1458     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1459 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1460 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1461     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1462     if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1463     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1464 vapier 1.39 }
1465 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1466 vapier 1.39
1467     /* now lets actually do the scanning */
1468 vapier 1.102 if (scan_ldpath || use_ldcache)
1469 vapier 1.48 load_ld_so_conf();
1470 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1471     if (scan_envpath) scanelf_envpath();
1472 solar 1.45 if (from_file) {
1473     scanelf_from_file(from_file);
1474     from_file = *argv;
1475     }
1476     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1477 vapier 1.25 err("Nothing to scan !?");
1478 vapier 1.66 while (optind < argc) {
1479     search_path = argv[optind++];
1480     scanelf_dir(search_path);
1481     }
1482 vapier 1.27
1483 vapier 1.39 /* clean up */
1484 vapier 1.93 if (versioned_symname) free(versioned_symname);
1485 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1486     free(ldpaths[i]);
1487 solar 1.96
1488     if (ldcache != 0)
1489     munmap(ldcache, ldcache_size);
1490 vapier 1.10 }
1491    
1492    
1493    
1494 vapier 1.41 /* utility funcs */
1495 vapier 1.60 static char *xstrdup(const char *s)
1496 vapier 1.41 {
1497     char *ret = strdup(s);
1498     if (!ret) err("Could not strdup(): %s", strerror(errno));
1499     return ret;
1500     }
1501     static void *xmalloc(size_t size)
1502     {
1503     void *ret = malloc(size);
1504     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1505     return ret;
1506     }
1507 vapier 1.95 static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1508 vapier 1.41 {
1509 vapier 1.69 size_t new_len;
1510 vapier 1.41
1511     new_len = strlen(*dst) + strlen(src);
1512     if (*curr_len <= new_len) {
1513     *curr_len = new_len + (*curr_len / 2);
1514     *dst = realloc(*dst, *curr_len);
1515     if (!*dst)
1516 vapier 1.95 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1517 vapier 1.41 }
1518    
1519 vapier 1.95 if (n)
1520     strncat(*dst, src, n);
1521     else
1522     strcat(*dst, src);
1523 vapier 1.41 }
1524     static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1525     {
1526     static char my_app[2];
1527     my_app[0] = append;
1528     my_app[1] = '\0';
1529     xstrcat(dst, my_app, curr_len);
1530     }
1531    
1532    
1533 vapier 1.72
1534 vapier 1.10 int main(int argc, char *argv[])
1535 solar 1.1 {
1536 vapier 1.10 if (argc < 2)
1537     usage(EXIT_FAILURE);
1538     parseargs(argc, argv);
1539 solar 1.21 fclose(stdout);
1540 solar 1.61 #ifdef __BOUNDS_CHECKING_ON
1541 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()");
1542 solar 1.61 #endif
1543 vapier 1.10 return EXIT_SUCCESS;
1544 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20