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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.118 - (hide annotations) (download) (as text)
Fri Feb 3 00:10:05 2006 UTC (8 years, 7 months ago) by vapier
Branch: MAIN
Changes since 1.117: +3 -3 lines
File MIME type: text/x-csrc
fix phdr scanning

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

  ViewVC Help
Powered by ViewVC 1.1.20