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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.210 - (hide annotations) (download) (as text)
Sun Mar 15 08:56:14 2009 UTC (5 years, 7 months ago) by vapier
Branch: MAIN
Changes since 1.209: +3 -3 lines
File MIME type: text/x-csrc
trick gcc into not warning about write() when outputting the banner -- we dont care if this fails

1 solar 1.1 /*
2 solar 1.178 * Copyright 2003-2007 Gentoo Foundation
3 solar 1.1 * Distributed under the terms of the GNU General Public License v2
4 vapier 1.210 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.209 2009/03/15 08:53:29 vapier Exp $
5 solar 1.1 *
6 solar 1.179 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org>
7     * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org>
8 solar 1.1 */
9    
10 vapier 1.210 static const char *rcsid = "$Id: scanelf.c,v 1.209 2009/03/15 08:53:29 vapier Exp $";
11 vapier 1.186 const char * const argv0 = "scanelf";
12    
13 vapier 1.89 #include "paxinc.h"
14 flameeyes 1.141
15 solar 1.132 #define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
16 vapier 1.70
17 vapier 1.10 /* prototypes */
18 kevquinn 1.142 static int file_matches_list(const char *filename, char **matchlist);
19 vapier 1.106 static int scanelf_elfobj(elfobj *elf);
20     static int scanelf_elf(const char *filename, int fd, size_t len);
21     static int scanelf_archive(const char *filename, int fd, size_t len);
22 solar 1.164 static int scanelf_file(const char *filename, const struct stat *st_cache);
23     static int scanelf_dir(const char *path);
24 vapier 1.106 static void scanelf_ldpath(void);
25     static void scanelf_envpath(void);
26 vapier 1.10 static void usage(int status);
27 kevquinn 1.142 static char **get_split_env(const char *envvar);
28     static void parseenv(void);
29 solar 1.164 static int parseargs(int argc, char *argv[]);
30 solar 1.174 static int rematch(const char *regex, const char *match, int cflags);
31 vapier 1.10
32     /* variables to control behavior */
33 solar 1.119 static char match_etypes[126] = "";
34 vapier 1.48 static char *ldpaths[256];
35 vapier 1.10 static char scan_ldpath = 0;
36     static char scan_envpath = 0;
37 vapier 1.37 static char scan_symlink = 1;
38 vapier 1.105 static char scan_archives = 0;
39 vapier 1.10 static char dir_recurse = 0;
40 vapier 1.14 static char dir_crossmount = 1;
41 vapier 1.10 static char show_pax = 0;
42 solar 1.180 static char show_perms = 0;
43 solar 1.190 static char show_size = 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 solar 1.181 static char show_endian = 0;
54 solar 1.191 static char show_osabi = 0;
55     static char show_eabi = 0;
56 vapier 1.10 static char be_quiet = 0;
57 vapier 1.14 static char be_verbose = 0;
58 solar 1.127 static char be_wewy_wewy_quiet = 0;
59 solar 1.132 static char be_semi_verbose = 0;
60 flameeyes 1.198 static char *find_sym = NULL;
61 vapier 1.72 static char *find_lib = NULL;
62 solar 1.124 static char *find_section = NULL;
63 vapier 1.39 static char *out_format = NULL;
64 vapier 1.66 static char *search_path = NULL;
65 vapier 1.101 static char fix_elf = 0;
66 solar 1.176 static char g_match = 0;
67 vapier 1.102 static char use_ldcache = 0;
68 solar 1.1
69 kevquinn 1.142 static char **qa_textrels = NULL;
70     static char **qa_execstack = NULL;
71 kevquinn 1.145 static char **qa_wx_load = NULL;
72 kevquinn 1.142
73 vapier 1.203 static int match_bits = 0;
74     static unsigned int match_perms = 0;
75     static caddr_t ldcache = 0;
76     static size_t ldcache_size = 0;
77     static unsigned long setpax = 0UL;
78 solar 1.96
79 vapier 1.203 static int has_objdump = 0;
80 solar 1.175
81 solar 1.174 /* find the path to a file by name */
82 solar 1.170 static char *which(const char *fname)
83     {
84 vapier 1.207 static char fullpath[__PAX_UTILS_PATH_MAX];
85 vapier 1.172 char *path, *p;
86 solar 1.170
87 vapier 1.172 path = getenv("PATH");
88     if (!path)
89 solar 1.170 return NULL;
90    
91 vapier 1.172 path = xstrdup(path);
92     while ((p = strrchr(path, ':')) != NULL) {
93 solar 1.170 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
94 vapier 1.172 *p = 0;
95 vapier 1.205 if (access(fullpath, R_OK) != -1) {
96 solar 1.170 free(path);
97 vapier 1.204 return fullpath;
98 solar 1.170 }
99 vapier 1.172 }
100     free(path);
101 solar 1.170 return NULL;
102     }
103 vapier 1.152
104 solar 1.175 /* 1 on failure. 0 otherwise */
105 solar 1.174 static int rematch(const char *regex, const char *match, int cflags)
106     {
107     regex_t preg;
108     int ret;
109    
110     if ((match == NULL) || (regex == NULL))
111     return EXIT_FAILURE;
112    
113     if ((ret = regcomp(&preg, regex, cflags))) {
114     char err[256];
115    
116     if (regerror(ret, &preg, err, sizeof(err)))
117     fprintf(stderr, "regcomp failed: %s", err);
118     else
119     fprintf(stderr, "regcomp failed");
120    
121     return EXIT_FAILURE;
122     }
123     ret = regexec(&preg, match, 0, NULL, 0);
124     regfree(&preg);
125    
126     return ret;
127     }
128    
129 vapier 1.39 /* sub-funcs for scanelf_file() */
130 vapier 1.77 static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
131     {
132     /* find the best SHT_DYNSYM and SHT_STRTAB sections */
133     #define GET_SYMTABS(B) \
134     if (elf->elf_class == ELFCLASS ## B) { \
135     Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
136     /* debug sections */ \
137     symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
138     strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
139     /* runtime sections */ \
140     dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
141     dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
142     if (symtab && dynsym) { \
143     *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
144     } else { \
145     *sym = (void*)(symtab ? symtab : dynsym); \
146     } \
147     if (strtab && dynstr) { \
148     *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
149     } else { \
150     *tab = (void*)(strtab ? strtab : dynstr); \
151     } \
152     }
153     GET_SYMTABS(32)
154     GET_SYMTABS(64)
155     }
156 solar 1.127
157 vapier 1.41 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
158 solar 1.6 {
159 solar 1.61 static char ret[7];
160     unsigned long i, shown;
161    
162 vapier 1.41 if (!show_pax) return NULL;
163 vapier 1.10
164 solar 1.61 shown = 0;
165     memset(&ret, 0, sizeof(ret));
166    
167     if (elf->phdr) {
168     #define SHOW_PAX(B) \
169     if (elf->elf_class == ELFCLASS ## B) { \
170     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
171     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
172     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
173     if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
174     continue; \
175 solar 1.127 if (fix_elf && setpax) { \
176     /* set the paxctl flags */ \
177     ESET(phdr[i].p_flags, setpax); \
178     } \
179 solar 1.129 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
180 solar 1.61 continue; \
181     memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
182     *found_pax = 1; \
183     ++shown; \
184     break; \
185     } \
186     }
187     SHOW_PAX(32)
188     SHOW_PAX(64)
189     }
190    
191 solar 1.128 if (fix_elf && setpax) {
192     /* set the chpax settings */
193 solar 1.129 if (elf->elf_class == ELFCLASS32) {
194     if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
195     ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
196     } else {
197     if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
198     ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
199     }
200 solar 1.128 }
201    
202 solar 1.61 /* fall back to EI_PAX if no PT_PAX was found */
203     if (!*ret) {
204 vapier 1.90 static char *paxflags;
205 solar 1.61 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
206     if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
207     *found_pax = 1;
208 solar 1.127 return (be_wewy_wewy_quiet ? NULL : paxflags);
209 solar 1.61 }
210     strncpy(ret, paxflags, sizeof(ret));
211 vapier 1.14 }
212 vapier 1.41
213 solar 1.127 if (be_wewy_wewy_quiet || (be_quiet && !shown))
214 solar 1.61 return NULL;
215 vapier 1.90 else
216     return ret;
217     }
218 solar 1.61
219 solar 1.73 static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
220 vapier 1.39 {
221 vapier 1.71 static char ret[12];
222 vapier 1.41 char *found;
223 vapier 1.99 unsigned long i, shown, multi_stack, multi_relro, multi_load;
224     int max_pt_load;
225 vapier 1.41
226 solar 1.73 if (!show_phdr) return NULL;
227 vapier 1.41
228 vapier 1.71 memcpy(ret, "--- --- ---\0", 12);
229    
230 vapier 1.41 shown = 0;
231 vapier 1.71 multi_stack = multi_relro = multi_load = 0;
232 vapier 1.99 max_pt_load = elf_max_pt_load(elf);
233 vapier 1.44
234 vapier 1.108 #define NOTE_GNU_STACK ".note.GNU-stack"
235 solar 1.73 #define SHOW_PHDR(B) \
236 vapier 1.39 if (elf->elf_class == ELFCLASS ## B) { \
237     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
238 vapier 1.91 Elf ## B ## _Off offset; \
239     uint32_t flags, check_flags; \
240     if (elf->phdr != NULL) { \
241     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
242     for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
243     if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
244 vapier 1.152 if (multi_stack++) \
245     warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
246     if (file_matches_list(elf->filename, qa_execstack)) \
247     continue; \
248     found = found_phdr; \
249     offset = 0; \
250     check_flags = PF_X; \
251 vapier 1.91 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
252 vapier 1.152 if (multi_relro++) \
253     warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
254 vapier 1.91 found = found_relro; \
255     offset = 4; \
256     check_flags = PF_X; \
257     } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
258 solar 1.188 if (EGET(ehdr->e_type) == ET_DYN || EGET(ehdr->e_type) == ET_EXEC) \
259 vapier 1.152 if (multi_load++ > max_pt_load) \
260     warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
261     if (file_matches_list(elf->filename, qa_wx_load)) \
262     continue; \
263     found = found_load; \
264     offset = 8; \
265     check_flags = PF_W|PF_X; \
266 vapier 1.91 } else \
267     continue; \
268     flags = EGET(phdr[i].p_flags); \
269     if (be_quiet && ((flags & check_flags) != check_flags)) \
270     continue; \
271 solar 1.130 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
272 vapier 1.101 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
273     ret[3] = ret[7] = '!'; \
274     flags = EGET(phdr[i].p_flags); \
275     } \
276 vapier 1.91 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
277     *found = 1; \
278     ++shown; \
279     } \
280     } else if (elf->shdr != NULL) { \
281     /* no program headers which means this is prob an object file */ \
282     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
283     Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
284 vapier 1.108 char *str; \
285 vapier 1.118 if ((void*)strtbl > (void*)elf->data_end) \
286 vapier 1.108 goto skip_this_shdr##B; \
287 vapier 1.91 check_flags = SHF_WRITE|SHF_EXECINSTR; \
288     for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
289     if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
290     offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
291 vapier 1.108 str = elf->data + offset; \
292     if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
293     if (!strcmp(str, NOTE_GNU_STACK)) { \
294 vapier 1.91 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
295     flags = EGET(shdr[i].sh_flags); \
296     if (be_quiet && ((flags & check_flags) != check_flags)) \
297     continue; \
298     ++*found_phdr; \
299     shown = 1; \
300     if (flags & SHF_WRITE) ret[0] = 'W'; \
301     if (flags & SHF_ALLOC) ret[1] = 'A'; \
302     if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
303     if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
304     break; \
305     } \
306     } \
307 vapier 1.108 skip_this_shdr##B: \
308 vapier 1.91 if (!multi_stack) { \
309 vapier 1.158 if (file_matches_list(elf->filename, qa_execstack)) \
310     return NULL; \
311 vapier 1.91 *found_phdr = 1; \
312     shown = 1; \
313     memcpy(ret, "!WX", 3); \
314     } \
315 vapier 1.39 } \
316     }
317 solar 1.73 SHOW_PHDR(32)
318     SHOW_PHDR(64)
319 vapier 1.44
320 solar 1.127 if (be_wewy_wewy_quiet || (be_quiet && !shown))
321 vapier 1.41 return NULL;
322     else
323     return ret;
324 vapier 1.39 }
325 kevquinn 1.142
326 vapier 1.186 /*
327     * See if this ELF contains a DT_TEXTREL tag in any of its
328     * PT_DYNAMIC sections.
329     */
330 vapier 1.90 static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
331 vapier 1.39 {
332 vapier 1.90 static const char *ret = "TEXTREL";
333 vapier 1.44 unsigned long i;
334 vapier 1.41
335 vapier 1.79 if (!show_textrel && !show_textrels) return NULL;
336 vapier 1.41
337 kevquinn 1.142 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
338    
339 vapier 1.44 if (elf->phdr) {
340 vapier 1.39 #define SHOW_TEXTREL(B) \
341     if (elf->elf_class == ELFCLASS ## B) { \
342     Elf ## B ## _Dyn *dyn; \
343     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
344     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
345 vapier 1.44 Elf ## B ## _Off offset; \
346 vapier 1.39 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
347 vapier 1.185 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
348 vapier 1.44 offset = EGET(phdr[i].p_offset); \
349     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
350     dyn = DYN ## B (elf->data + offset); \
351 vapier 1.39 while (EGET(dyn->d_tag) != DT_NULL) { \
352     if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
353     *found_textrel = 1; \
354     /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
355 solar 1.127 return (be_wewy_wewy_quiet ? NULL : ret); \
356 vapier 1.39 } \
357     ++dyn; \
358 vapier 1.26 } \
359 vapier 1.39 } }
360     SHOW_TEXTREL(32)
361     SHOW_TEXTREL(64)
362 vapier 1.44 }
363    
364 solar 1.127 if (be_quiet || be_wewy_wewy_quiet)
365 vapier 1.41 return NULL;
366     else
367 vapier 1.90 return " - ";
368 vapier 1.39 }
369 solar 1.180
370 vapier 1.186 /*
371     * Scan the .text section to see if there are any relocations in it.
372     * Should rewrite this to check PT_LOAD sections that are marked
373     * Executable rather than the section named '.text'.
374     */
375 vapier 1.79 static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
376 vapier 1.76 {
377 vapier 1.82 unsigned long s, r, rmax;
378     void *symtab_void, *strtab_void, *text_void;
379 vapier 1.76
380     if (!show_textrels) return NULL;
381    
382 vapier 1.79 /* don't search for TEXTREL's if the ELF doesn't have any */
383     if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
384     if (!*found_textrel) return NULL;
385    
386 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
387 vapier 1.82 text_void = elf_findsecbyname(elf, ".text");
388 vapier 1.76
389 vapier 1.82 if (symtab_void && strtab_void && text_void && elf->shdr) {
390 vapier 1.76 #define SHOW_TEXTRELS(B) \
391     if (elf->elf_class == ELFCLASS ## B) { \
392     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
393     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
394     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
395     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
396 vapier 1.82 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
397     Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
398     uint ## B ## _t memsz = EGET(text->sh_size); \
399 vapier 1.76 Elf ## B ## _Rel *rel; \
400     Elf ## B ## _Rela *rela; \
401     /* search the section headers for relocations */ \
402     for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
403     uint32_t sh_type = EGET(shdr[s].sh_type); \
404     if (sh_type == SHT_REL) { \
405     rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
406     rela = NULL; \
407     rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
408     } else if (sh_type == SHT_RELA) { \
409     rel = NULL; \
410     rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
411     rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
412     } else \
413     continue; \
414 vapier 1.82 /* now see if any of the relocs are in the .text */ \
415     for (r = 0; r < rmax; ++r) { \
416     unsigned long sym_max; \
417     Elf ## B ## _Addr offset_tmp; \
418     Elf ## B ## _Sym *func; \
419     Elf ## B ## _Sym *sym; \
420     Elf ## B ## _Addr r_offset; \
421     uint ## B ## _t r_info; \
422     if (sh_type == SHT_REL) { \
423     r_offset = EGET(rel[r].r_offset); \
424     r_info = EGET(rel[r].r_info); \
425     } else { \
426     r_offset = EGET(rela[r].r_offset); \
427     r_info = EGET(rela[r].r_info); \
428     } \
429     /* make sure this relocation is inside of the .text */ \
430     if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
431     if (be_verbose <= 2) continue; \
432     } else \
433 vapier 1.78 *found_textrels = 1; \
434 vapier 1.82 /* locate this relocation symbol name */ \
435     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
436 vapier 1.112 if ((void*)sym > (void*)elf->data_end) { \
437 vapier 1.111 warn("%s: corrupt ELF symbol", elf->filename); \
438 vapier 1.109 continue; \
439     } \
440 vapier 1.82 sym_max = ELF ## B ## _R_SYM(r_info); \
441     if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
442     sym += sym_max; \
443     else \
444     sym = NULL; \
445     sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
446     /* show the raw details about this reloc */ \
447 vapier 1.88 printf(" %s: ", elf->base_filename); \
448 vapier 1.82 if (sym && sym->st_name) \
449     printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
450     else \
451 vapier 1.169 printf("(memory/data?)"); \
452 vapier 1.82 printf(" [0x%lX]", (unsigned long)r_offset); \
453     /* now try to find the closest symbol that this rel is probably in */ \
454     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
455     func = NULL; \
456     offset_tmp = 0; \
457     while (sym_max--) { \
458     if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
459     func = sym; \
460     offset_tmp = EGET(sym->st_value); \
461 vapier 1.76 } \
462 vapier 1.82 ++sym; \
463 vapier 1.76 } \
464 vapier 1.82 printf(" in "); \
465 vapier 1.169 if (func && func->st_name) { \
466     const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
467     if (r_offset > EGET(func->st_size)) \
468     printf("(optimized out: previous %s)", func_name); \
469     else \
470     printf("%s", func_name); \
471     } else \
472     printf("(optimized out)"); \
473 vapier 1.82 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
474 solar 1.170 if (be_verbose && has_objdump) { \
475 vapier 1.187 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
476 vapier 1.167 char *sysbuf; \
477     size_t syslen; \
478 vapier 1.209 int sysret; \
479 vapier 1.167 const char sysfmt[] = "objdump -r -R -d -w -l --start-address=0x%lX --stop-address=0x%lX %s | grep --color -i -C 3 '.*[[:space:]]%lX:[[:space:]]*R_.*'\n"; \
480     syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
481     sysbuf = xmalloc(syslen); \
482 vapier 1.187 if (end_addr < r_offset) \
483     /* not uncommon when things are optimized out */ \
484     end_addr = r_offset + 0x100; \
485     snprintf(sysbuf, syslen, sysfmt, \
486     (unsigned long)offset_tmp, \
487     (unsigned long)end_addr, \
488     elf->filename, \
489     (unsigned long)r_offset); \
490     fflush(stdout); \
491 vapier 1.209 sysret = system(sysbuf); \
492 vapier 1.187 fflush(stdout); \
493     free(sysbuf); \
494 vapier 1.167 } \
495 vapier 1.76 } \
496     } }
497     SHOW_TEXTRELS(32)
498     SHOW_TEXTRELS(64)
499     }
500 vapier 1.82 if (!*found_textrels)
501     warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
502 vapier 1.76
503     return NULL;
504     }
505 solar 1.83
506 vapier 1.102 static void rpath_security_checks(elfobj *, char *, const char *);
507     static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
508 vapier 1.100 {
509 solar 1.83 struct stat st;
510 vapier 1.84 switch (*item) {
511 vapier 1.89 case '/': break;
512     case '.':
513 vapier 1.102 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
514 vapier 1.89 break;
515 vapier 1.100 case ':':
516 vapier 1.89 case '\0':
517 vapier 1.102 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
518 solar 1.83 break;
519     case '$':
520 vapier 1.84 if (fstat(elf->fd, &st) != -1)
521 solar 1.83 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
522 vapier 1.157 warnf("Security problem with %s='%s' in %s with mode set of %o",
523 solar 1.176 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
524 solar 1.83 break;
525     default:
526 vapier 1.102 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
527 solar 1.83 break;
528     }
529     }
530 vapier 1.41 static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
531 vapier 1.39 {
532 vapier 1.48 unsigned long i, s;
533     char *rpath, *runpath, **r;
534 vapier 1.39 void *strtbl_void;
535 vapier 1.10
536 vapier 1.39 if (!show_rpath) return;
537 vapier 1.10
538 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
539     rpath = runpath = NULL;
540 vapier 1.10
541 vapier 1.44 if (elf->phdr && strtbl_void) {
542 vapier 1.26 #define SHOW_RPATH(B) \
543     if (elf->elf_class == ELFCLASS ## B) { \
544     Elf ## B ## _Dyn *dyn; \
545     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
546     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
547     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
548 vapier 1.44 Elf ## B ## _Off offset; \
549 vapier 1.60 Elf ## B ## _Xword word; \
550 vapier 1.48 /* Scan all the program headers */ \
551 vapier 1.26 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
552 vapier 1.48 /* Just scan dynamic headers */ \
553 vapier 1.185 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
554 vapier 1.44 offset = EGET(phdr[i].p_offset); \
555     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
556 vapier 1.48 /* Just scan dynamic RPATH/RUNPATH headers */ \
557 vapier 1.44 dyn = DYN ## B (elf->data + offset); \
558 vapier 1.48 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
559     if (word == DT_RPATH) { \
560     r = &rpath; \
561     } else if (word == DT_RUNPATH) { \
562     r = &runpath; \
563     } else { \
564     ++dyn; \
565     continue; \
566     } \
567     /* Verify the memory is somewhat sane */ \
568     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
569 vapier 1.69 if (offset < (Elf ## B ## _Off)elf->len) { \
570 vapier 1.48 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
571     *r = (char*)(elf->data + offset); \
572 vapier 1.103 /* cache the length in case we need to nuke this section later on */ \
573     if (fix_elf) \
574     offset = strlen(*r); \
575 vapier 1.48 /* If quiet, don't output paths in ld.so.conf */ \
576 vapier 1.69 if (be_quiet) { \
577     size_t len; \
578     char *start, *end; \
579 vapier 1.75 /* note that we only 'chop' off leading known paths. */ \
580     /* since *r is read-only memory, we can only move the ptr forward. */ \
581     start = *r; \
582     /* scan each path in : delimited list */ \
583     while (start) { \
584 vapier 1.102 rpath_security_checks(elf, start, get_elfdtype(word)); \
585 vapier 1.69 end = strchr(start, ':'); \
586 vapier 1.75 len = (end ? abs(end - start) : strlen(start)); \
587 vapier 1.102 if (use_ldcache) \
588     for (s = 0; ldpaths[s]; ++s) \
589     if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
590     *r = end; \
591     /* corner case ... if RPATH reads "/usr/lib:", we want \
592     * to show ':' rather than '' */ \
593     if (end && end[1] != '\0') \
594     (*r)++; \
595     break; \
596     } \
597 vapier 1.100 if (!*r || !end) \
598     break; \
599 vapier 1.75 else \
600     start = start + len + 1; \
601 vapier 1.69 } \
602     } \
603 vapier 1.101 if (*r) { \
604 solar 1.107 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
605 vapier 1.101 /* just nuke it */ \
606     nuke_it##B: \
607 vapier 1.103 memset(*r, 0x00, offset); \
608 vapier 1.102 *r = NULL; \
609 vapier 1.101 ESET(dyn->d_tag, DT_DEBUG); \
610 vapier 1.103 ESET(dyn->d_un.d_ptr, 0); \
611 vapier 1.101 } else if (fix_elf) { \
612     /* try to clean "bad" paths */ \
613     size_t len, tmpdir_len; \
614     char *start, *end; \
615     const char *tmpdir; \
616     start = *r; \
617     tmpdir = (getenv("TMPDIR") ? : "."); \
618     tmpdir_len = strlen(tmpdir); \
619     while (1) { \
620     end = strchr(start, ':'); \
621     if (start == end) { \
622     eat_this_path##B: \
623     len = strlen(end); \
624     memmove(start, end+1, len); \
625     start[len-1] = '\0'; \
626     end = start - 1; \
627     } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
628     if (!end) { \
629     if (start == *r) \
630     goto nuke_it##B; \
631     *--start = '\0'; \
632     } else \
633     goto eat_this_path##B; \
634     } \
635     if (!end) \
636     break; \
637     start = end + 1; \
638     } \
639 vapier 1.102 if (**r == '\0') \
640     goto nuke_it##B; \
641 vapier 1.101 } \
642 vapier 1.102 if (*r) \
643     *found_rpath = 1; \
644 vapier 1.101 } \
645 vapier 1.26 } \
646     ++dyn; \
647     } \
648     } }
649     SHOW_RPATH(32)
650     SHOW_RPATH(64)
651 vapier 1.10 }
652 vapier 1.41
653 solar 1.127 if (be_wewy_wewy_quiet) return;
654 vapier 1.70
655 vapier 1.39 if (rpath && runpath) {
656 vapier 1.41 if (!strcmp(rpath, runpath)) {
657     xstrcat(ret, runpath, ret_len);
658     } else {
659 vapier 1.39 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
660 vapier 1.41 xchrcat(ret, '{', ret_len);
661     xstrcat(ret, rpath, ret_len);
662     xchrcat(ret, ',', ret_len);
663     xstrcat(ret, runpath, ret_len);
664     xchrcat(ret, '}', ret_len);
665 vapier 1.39 }
666     } else if (rpath || runpath)
667 vapier 1.41 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
668     else if (!be_quiet)
669     xstrcat(ret, " - ", ret_len);
670 vapier 1.39 }
671 solar 1.96
672     #define LDSO_CACHE_MAGIC "ld.so-"
673     #define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
674     #define LDSO_CACHE_VER "1.7.0"
675     #define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
676 vapier 1.97 #define FLAG_ANY -1
677     #define FLAG_TYPE_MASK 0x00ff
678     #define FLAG_LIBC4 0x0000
679     #define FLAG_ELF 0x0001
680     #define FLAG_ELF_LIBC5 0x0002
681     #define FLAG_ELF_LIBC6 0x0003
682     #define FLAG_REQUIRED_MASK 0xff00
683     #define FLAG_SPARC_LIB64 0x0100
684     #define FLAG_IA64_LIB64 0x0200
685     #define FLAG_X8664_LIB64 0x0300
686     #define FLAG_S390_LIB64 0x0400
687     #define FLAG_POWERPC_LIB64 0x0500
688     #define FLAG_MIPS64_LIBN32 0x0600
689     #define FLAG_MIPS64_LIBN64 0x0700
690 solar 1.96
691 vapier 1.97 static char *lookup_cache_lib(elfobj *, char *);
692 vapier 1.148
693 flameeyes 1.141 #if defined(__GLIBC__) || defined(__UCLIBC__)
694 vapier 1.148
695 vapier 1.97 static char *lookup_cache_lib(elfobj *elf, char *fname)
696 solar 1.96 {
697     int fd = 0;
698     char *strs;
699 vapier 1.104 static char buf[__PAX_UTILS_PATH_MAX] = "";
700 solar 1.96 const char *cachefile = "/etc/ld.so.cache";
701     struct stat st;
702    
703     typedef struct {
704     char magic[LDSO_CACHE_MAGIC_LEN];
705     char version[LDSO_CACHE_VER_LEN];
706     int nlibs;
707     } header_t;
708 vapier 1.97 header_t *header;
709 solar 1.96
710     typedef struct {
711     int flags;
712     int sooffset;
713     int liboffset;
714     } libentry_t;
715     libentry_t *libent;
716    
717     if (fname == NULL)
718     return NULL;
719    
720     if (ldcache == 0) {
721 vapier 1.97 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
722 solar 1.96 return NULL;
723 vapier 1.97
724     /* cache these values so we only map/unmap the cache file once */
725 solar 1.96 ldcache_size = st.st_size;
726 vapier 1.97 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
727    
728     close(fd);
729 solar 1.96
730 vapier 1.202 if (ldcache == MAP_FAILED) {
731 solar 1.116 ldcache = 0;
732 solar 1.96 return NULL;
733 solar 1.116 }
734 solar 1.96
735     if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
736     return NULL;
737     if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
738     return NULL;
739     }
740    
741     header = (header_t *) ldcache;
742     libent = (libentry_t *) (ldcache + sizeof(header_t));
743     strs = (char *) &libent[header->nlibs];
744    
745     for (fd = 0; fd < header->nlibs; fd++) {
746 vapier 1.97 /* this should be more fine grained, but for now we assume that
747     * diff arches will not be cached together. and we ignore the
748     * the different multilib mips cases. */
749     if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
750     continue;
751     if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
752     continue;
753    
754 solar 1.96 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
755     continue;
756     strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
757     }
758     return buf;
759     }
760 solar 1.154 #elif defined(__NetBSD__)
761     static char *lookup_cache_lib(elfobj *elf, char *fname)
762     {
763     static char buf[__PAX_UTILS_PATH_MAX] = "";
764     static struct stat st;
765    
766     char **ldpath;
767     for (ldpath = ldpaths; *ldpath != NULL; ldpath++) {
768     if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf))
769     continue; /* if the pathname is too long, or something went wrong, ignore */
770    
771     if (stat(buf, &st) != 0)
772     continue; /* if the lib doesn't exist in *ldpath, look further */
773    
774     /* NetBSD doesn't actually do sanity checks, it just loads the file
775     * and if that doesn't work, continues looking in other directories.
776     * This cannot easily be safely emulated, unfortunately. For now,
777     * just assume that if it exists, it's a valid library. */
778 vapier 1.148
779 solar 1.154 return buf;
780     }
781    
782     /* not found in any path */
783     return NULL;
784     }
785 flameeyes 1.141 #else
786 vapier 1.192 #ifdef __ELF__
787 vapier 1.148 #warning Cache support not implemented for your target
788 vapier 1.192 #endif
789 flameeyes 1.141 static char *lookup_cache_lib(elfobj *elf, char *fname)
790     {
791     return NULL;
792     }
793     #endif
794 solar 1.96
795 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)
796 vapier 1.39 {
797 vapier 1.44 unsigned long i;
798 vapier 1.39 char *needed;
799     void *strtbl_void;
800 solar 1.96 char *p;
801 vapier 1.39
802 vapier 1.72 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
803 vapier 1.10
804 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
805 vapier 1.32
806 vapier 1.44 if (elf->phdr && strtbl_void) {
807 vapier 1.32 #define SHOW_NEEDED(B) \
808     if (elf->elf_class == ELFCLASS ## B) { \
809     Elf ## B ## _Dyn *dyn; \
810     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
811     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
812     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
813 vapier 1.44 Elf ## B ## _Off offset; \
814 vapier 1.32 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
815 vapier 1.185 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
816 vapier 1.44 offset = EGET(phdr[i].p_offset); \
817     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
818     dyn = DYN ## B (elf->data + offset); \
819 vapier 1.32 while (EGET(dyn->d_tag) != DT_NULL) { \
820     if (EGET(dyn->d_tag) == DT_NEEDED) { \
821 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
822 vapier 1.69 if (offset >= (Elf ## B ## _Off)elf->len) { \
823 vapier 1.49 ++dyn; \
824     continue; \
825     } \
826 vapier 1.44 needed = (char*)(elf->data + offset); \
827 vapier 1.72 if (op == 0) { \
828 solar 1.127 if (!be_wewy_wewy_quiet) { \
829 vapier 1.72 if (*found_needed) xchrcat(ret, ',', ret_len); \
830 vapier 1.102 if (use_ldcache) \
831 vapier 1.97 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
832 solar 1.96 needed = p; \
833 vapier 1.72 xstrcat(ret, needed, ret_len); \
834     } \
835     *found_needed = 1; \
836     } else { \
837 solar 1.176 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \
838 vapier 1.81 *found_lib = 1; \
839 solar 1.127 return (be_wewy_wewy_quiet ? NULL : needed); \
840 vapier 1.81 } \
841 vapier 1.72 } \
842 vapier 1.32 } \
843     ++dyn; \
844     } \
845     } }
846     SHOW_NEEDED(32)
847     SHOW_NEEDED(64)
848 vapier 1.85 if (op == 0 && !*found_needed && be_verbose)
849 vapier 1.84 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
850 vapier 1.32 }
851 vapier 1.72
852     return NULL;
853 vapier 1.39 }
854 vapier 1.41 static char *scanelf_file_interp(elfobj *elf, char *found_interp)
855 vapier 1.39 {
856     void *strtbl_void;
857    
858 vapier 1.41 if (!show_interp) return NULL;
859 vapier 1.32
860 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".interp");
861 vapier 1.38
862 vapier 1.39 if (strtbl_void) {
863 vapier 1.38 #define SHOW_INTERP(B) \
864     if (elf->elf_class == ELFCLASS ## B) { \
865 solar 1.40 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
866     *found_interp = 1; \
867 solar 1.127 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
868 vapier 1.38 }
869     SHOW_INTERP(32)
870     SHOW_INTERP(64)
871     }
872 vapier 1.41 return NULL;
873 vapier 1.39 }
874 vapier 1.49 static char *scanelf_file_bind(elfobj *elf, char *found_bind)
875     {
876     unsigned long i;
877     struct stat s;
878 solar 1.131 char dynamic = 0;
879 vapier 1.49
880     if (!show_bind) return NULL;
881 vapier 1.51 if (!elf->phdr) return NULL;
882 vapier 1.49
883     #define SHOW_BIND(B) \
884     if (elf->elf_class == ELFCLASS ## B) { \
885     Elf ## B ## _Dyn *dyn; \
886     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
887     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
888     Elf ## B ## _Off offset; \
889     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
890 vapier 1.185 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
891 solar 1.131 dynamic = 1; \
892 vapier 1.49 offset = EGET(phdr[i].p_offset); \
893     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
894     dyn = DYN ## B (elf->data + offset); \
895     while (EGET(dyn->d_tag) != DT_NULL) { \
896     if (EGET(dyn->d_tag) == DT_BIND_NOW || \
897     (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
898     { \
899     if (be_quiet) return NULL; \
900     *found_bind = 1; \
901 solar 1.127 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
902 vapier 1.49 } \
903     ++dyn; \
904     } \
905     } \
906     }
907     SHOW_BIND(32)
908     SHOW_BIND(64)
909    
910 solar 1.127 if (be_wewy_wewy_quiet) return NULL;
911 vapier 1.70
912 vapier 1.159 /* don't output anything if quiet mode and the ELF is static or not setuid */
913     if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
914 vapier 1.49 return NULL;
915     } else {
916     *found_bind = 1;
917 solar 1.131 return (char *) (dynamic ? "LAZY" : "STATIC");
918 vapier 1.49 }
919     }
920 vapier 1.84 static char *scanelf_file_soname(elfobj *elf, char *found_soname)
921     {
922     unsigned long i;
923     char *soname;
924     void *strtbl_void;
925    
926     if (!show_soname) return NULL;
927    
928     strtbl_void = elf_findsecbyname(elf, ".dynstr");
929    
930     if (elf->phdr && strtbl_void) {
931     #define SHOW_SONAME(B) \
932     if (elf->elf_class == ELFCLASS ## B) { \
933     Elf ## B ## _Dyn *dyn; \
934     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
935     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
936     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
937     Elf ## B ## _Off offset; \
938     /* only look for soname in shared objects */ \
939 solar 1.188 if (EGET(ehdr->e_type) != ET_DYN) \
940 vapier 1.84 return NULL; \
941     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
942 vapier 1.185 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
943 vapier 1.84 offset = EGET(phdr[i].p_offset); \
944     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
945     dyn = DYN ## B (elf->data + offset); \
946     while (EGET(dyn->d_tag) != DT_NULL) { \
947     if (EGET(dyn->d_tag) == DT_SONAME) { \
948     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
949     if (offset >= (Elf ## B ## _Off)elf->len) { \
950     ++dyn; \
951     continue; \
952     } \
953     soname = (char*)(elf->data + offset); \
954     *found_soname = 1; \
955 solar 1.127 return (be_wewy_wewy_quiet ? NULL : soname); \
956 vapier 1.84 } \
957     ++dyn; \
958     } \
959     } }
960     SHOW_SONAME(32)
961     SHOW_SONAME(64)
962     }
963    
964     return NULL;
965     }
966 solar 1.177
967 flameeyes 1.198 static int scanelf_match_symname(const char *symname, const char *tomatch) {
968 flameeyes 1.197 /* We do things differently when checking with regexp */
969     if (g_match) {
970 flameeyes 1.198 return rematch(symname, tomatch, REG_EXTENDED) == 0;
971 flameeyes 1.197 } else {
972     const size_t symname_len = strlen(symname);
973 flameeyes 1.198 return (strncmp(symname, tomatch, symname_len) == 0 &&
974     /* Accept unversioned symbol names */
975     (tomatch[symname_len] == '\0' || tomatch[symname_len] == '@'));
976 flameeyes 1.197 }
977     }
978    
979 vapier 1.72 static char *scanelf_file_sym(elfobj *elf, char *found_sym)
980 vapier 1.39 {
981 vapier 1.44 unsigned long i;
982 vapier 1.95 char *ret;
983 vapier 1.39 void *symtab_void, *strtab_void;
984 vapier 1.38
985 vapier 1.41 if (!find_sym) return NULL;
986 vapier 1.95 ret = find_sym;
987 vapier 1.32
988 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
989 vapier 1.27
990 vapier 1.39 if (symtab_void && strtab_void) {
991 vapier 1.27 #define FIND_SYM(B) \
992     if (elf->elf_class == ELFCLASS ## B) { \
993     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
994     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
995     Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
996 vapier 1.115 unsigned long cnt = EGET(symtab->sh_entsize); \
997 vapier 1.27 char *symname; \
998 vapier 1.115 if (cnt) \
999     cnt = EGET(symtab->sh_size) / cnt; \
1000 vapier 1.27 for (i = 0; i < cnt; ++i) { \
1001 flameeyes 1.196 if ((void*)sym > (void*)elf->data_end) { \
1002 flameeyes 1.195 warnf("%s: corrupt ELF symbols - aborting", elf->filename); \
1003     goto break_out; \
1004     } \
1005 vapier 1.27 if (sym->st_name) { \
1006 vapier 1.134 /* make sure the symbol name is in acceptable memory range */ \
1007 vapier 1.27 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
1008 vapier 1.115 if ((void*)symname > (void*)elf->data_end) { \
1009     warnf("%s: corrupt ELF symbols", elf->filename); \
1010 vapier 1.134 ++sym; \
1011 vapier 1.111 continue; \
1012     } \
1013 vapier 1.134 /* debug display ... show all symbols and some extra info */ \
1014 flameeyes 1.197 if (0 && g_match ? rematch(ret, symname, REG_EXTENDED) == 0 : *ret == '*') { \
1015 solar 1.177 printf("%s(%s) %5lX %15s %s %s\n", \
1016 vapier 1.39 ((*found_sym == 0) ? "\n\t" : "\t"), \
1017 vapier 1.76 elf->base_filename, \
1018 vapier 1.94 (unsigned long)sym->st_size, \
1019 vapier 1.95 get_elfstttype(sym->st_info), \
1020 solar 1.177 sym->st_shndx == SHN_UNDEF ? "U" : "D", symname); \
1021 vapier 1.39 *found_sym = 1; \
1022 vapier 1.95 } else { \
1023 vapier 1.134 /* allow the user to specify a comma delimited list of symbols to search for */ \
1024 flameeyes 1.198 char *this_sym, *next_sym; \
1025 flameeyes 1.197 next_sym = ret; \
1026     while (next_sym) { \
1027     this_sym = next_sym; \
1028     if ((next_sym = strchr(this_sym, ','))) \
1029 grobian 1.200 next_sym += 1; /* Skip the comma */ \
1030 vapier 1.134 /* do we want a defined symbol ? */ \
1031     if (*this_sym == '+') { \
1032 vapier 1.140 if (sym->st_shndx == SHN_UNDEF) \
1033 flameeyes 1.197 continue; \
1034 vapier 1.134 ++this_sym; \
1035     /* do we want an undefined symbol ? */ \
1036     } else if (*this_sym == '-') { \
1037 vapier 1.140 if (sym->st_shndx != SHN_UNDEF) \
1038 flameeyes 1.197 continue; \
1039 vapier 1.134 ++this_sym; \
1040     } \
1041 grobian 1.200 if (next_sym) /* Copy it so that we don't have to worry about the final , */ \
1042 grobian 1.208 this_sym = xstrndup(this_sym, next_sym-this_sym); \
1043 vapier 1.134 /* ok, lets compare the name now */ \
1044 flameeyes 1.198 if (scanelf_match_symname(this_sym, symname)) { \
1045 solar 1.132 if (be_semi_verbose) { \
1046     char buf[126]; \
1047     snprintf(buf, sizeof(buf), "%lX %s %s", \
1048     (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
1049     ret = buf; \
1050     } else \
1051 flameeyes 1.197 ret = symname; \
1052 vapier 1.95 (*found_sym)++; \
1053     goto break_out; \
1054     } \
1055 grobian 1.200 if (next_sym) free(this_sym); \
1056 flameeyes 1.197 } \
1057 vapier 1.95 } \
1058 vapier 1.27 } \
1059     ++sym; \
1060     } }
1061     FIND_SYM(32)
1062     FIND_SYM(64)
1063 vapier 1.39 }
1064 vapier 1.70
1065 vapier 1.95 break_out:
1066 solar 1.127 if (be_wewy_wewy_quiet) return NULL;
1067 vapier 1.70
1068 vapier 1.41 if (*find_sym != '*' && *found_sym)
1069 vapier 1.95 return ret;
1070 vapier 1.41 if (be_quiet)
1071     return NULL;
1072     else
1073 solar 1.68 return (char *)" - ";
1074 vapier 1.39 }
1075 solar 1.119
1076 solar 1.124 static char *scanelf_file_sections(elfobj *elf, char *found_section)
1077     {
1078     if (!find_section)
1079     return NULL;
1080    
1081     #define FIND_SECTION(B) \
1082     if (elf->elf_class == ELFCLASS ## B) { \
1083 solar 1.136 int invert; \
1084 solar 1.124 Elf ## B ## _Shdr *section; \
1085 solar 1.136 invert = (*find_section == '!' ? 1 : 0); \
1086     section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
1087     if ((section == NULL && invert) || (section != NULL && !invert)) \
1088 solar 1.124 *found_section = 1; \
1089     }
1090     FIND_SECTION(32)
1091     FIND_SECTION(64)
1092    
1093 vapier 1.138 if (be_wewy_wewy_quiet)
1094     return NULL;
1095 solar 1.124
1096     if (*found_section)
1097     return find_section;
1098    
1099     if (be_quiet)
1100     return NULL;
1101     else
1102     return (char *)" - ";
1103     }
1104    
1105 vapier 1.39 /* scan an elf file and show all the fun stuff */
1106 vapier 1.210 #define prints(str) ({ ssize_t ret = write(fileno(stdout), str, strlen(str)); ret; })
1107 vapier 1.106 static int scanelf_elfobj(elfobj *elf)
1108 vapier 1.39 {
1109 vapier 1.44 unsigned long i;
1110 vapier 1.162 char found_pax, found_phdr, found_relro, found_load, found_textrel,
1111     found_rpath, found_needed, found_interp, found_bind, found_soname,
1112 solar 1.124 found_sym, found_lib, found_file, found_textrels, found_section;
1113 vapier 1.41 static char *out_buffer = NULL;
1114     static size_t out_len;
1115 vapier 1.39
1116 vapier 1.76 found_pax = found_phdr = found_relro = found_load = found_textrel = \
1117 vapier 1.84 found_rpath = found_needed = found_interp = found_bind = found_soname = \
1118 solar 1.124 found_sym = found_lib = found_file = found_textrels = found_section = 0;
1119 vapier 1.39
1120 vapier 1.114 if (be_verbose > 2)
1121 vapier 1.106 printf("%s: scanning file {%s,%s}\n", elf->filename,
1122 vapier 1.69 get_elfeitype(EI_CLASS, elf->elf_class),
1123     get_elfeitype(EI_DATA, elf->data[EI_DATA]));
1124 vapier 1.114 else if (be_verbose > 1)
1125 vapier 1.106 printf("%s: scanning file\n", elf->filename);
1126 vapier 1.39
1127 vapier 1.41 /* init output buffer */
1128     if (!out_buffer) {
1129     out_len = sizeof(char) * 80;
1130 vapier 1.186 out_buffer = xmalloc(out_len);
1131 vapier 1.41 }
1132     *out_buffer = '\0';
1133    
1134 vapier 1.39 /* show the header */
1135     if (!be_quiet && show_banner) {
1136 vapier 1.49 for (i = 0; out_format[i]; ++i) {
1137 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1138 vapier 1.41
1139     switch (out_format[++i]) {
1140 solar 1.132 case '+': break;
1141 vapier 1.41 case '%': break;
1142 vapier 1.70 case '#': break;
1143 vapier 1.66 case 'F':
1144     case 'p':
1145     case 'f': prints("FILE "); found_file = 1; break;
1146 vapier 1.41 case 'o': prints(" TYPE "); break;
1147     case 'x': prints(" PAX "); break;
1148 vapier 1.71 case 'e': prints("STK/REL/PTL "); break;
1149 vapier 1.41 case 't': prints("TEXTREL "); break;
1150     case 'r': prints("RPATH "); break;
1151 vapier 1.171 case 'M': prints("CLASS "); break;
1152 vapier 1.41 case 'n': prints("NEEDED "); break;
1153     case 'i': prints("INTERP "); break;
1154 vapier 1.49 case 'b': prints("BIND "); break;
1155 solar 1.190 case 'Z': prints("SIZE "); break;
1156 vapier 1.84 case 'S': prints("SONAME "); break;
1157 vapier 1.41 case 's': prints("SYM "); break;
1158 vapier 1.72 case 'N': prints("LIB "); break;
1159 vapier 1.76 case 'T': prints("TEXTRELS "); break;
1160 vapier 1.126 case 'k': prints("SECTION "); break;
1161 vapier 1.166 case 'a': prints("ARCH "); break;
1162 solar 1.191 case 'I': prints("OSABI "); break;
1163     case 'Y': prints("EABI "); break;
1164 solar 1.180 case 'O': prints("PERM "); break;
1165 solar 1.181 case 'D': prints("ENDIAN "); break;
1166 vapier 1.76 default: warnf("'%c' has no title ?", out_format[i]);
1167 vapier 1.39 }
1168 vapier 1.27 }
1169 vapier 1.49 if (!found_file) prints("FILE ");
1170 vapier 1.41 prints("\n");
1171 vapier 1.49 found_file = 0;
1172 vapier 1.39 show_banner = 0;
1173     }
1174    
1175     /* dump all the good stuff */
1176 vapier 1.49 for (i = 0; out_format[i]; ++i) {
1177 vapier 1.41 const char *out;
1178 vapier 1.66 const char *tmp;
1179 solar 1.190 static char ubuf[sizeof(unsigned long)*2];
1180 vapier 1.70 if (!IS_MODIFIER(out_format[i])) {
1181 vapier 1.41 xchrcat(&out_buffer, out_format[i], &out_len);
1182     continue;
1183     }
1184 vapier 1.39
1185 vapier 1.41 out = NULL;
1186 solar 1.127 be_wewy_wewy_quiet = (out_format[i] == '#');
1187 solar 1.132 be_semi_verbose = (out_format[i] == '+');
1188 vapier 1.41 switch (out_format[++i]) {
1189 solar 1.132 case '+':
1190 vapier 1.70 case '%':
1191     case '#':
1192     xchrcat(&out_buffer, out_format[i], &out_len); break;
1193     case 'F':
1194 vapier 1.76 found_file = 1;
1195 solar 1.127 if (be_wewy_wewy_quiet) break;
1196 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1197 vapier 1.70 break;
1198 vapier 1.66 case 'p':
1199 vapier 1.76 found_file = 1;
1200 solar 1.127 if (be_wewy_wewy_quiet) break;
1201 vapier 1.106 tmp = elf->filename;
1202 vapier 1.66 if (search_path) {
1203     ssize_t len_search = strlen(search_path);
1204 vapier 1.106 ssize_t len_file = strlen(elf->filename);
1205     if (!strncmp(elf->filename, search_path, len_search) && \
1206 vapier 1.66 len_file > len_search)
1207     tmp += len_search;
1208     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
1209     }
1210     xstrcat(&out_buffer, tmp, &out_len);
1211     break;
1212     case 'f':
1213 vapier 1.76 found_file = 1;
1214 solar 1.127 if (be_wewy_wewy_quiet) break;
1215 vapier 1.106 tmp = strrchr(elf->filename, '/');
1216     tmp = (tmp == NULL ? elf->filename : tmp+1);
1217 vapier 1.66 xstrcat(&out_buffer, tmp, &out_len);
1218     break;
1219 vapier 1.41 case 'o': out = get_elfetype(elf); break;
1220     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1221 solar 1.73 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1222 vapier 1.41 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1223 vapier 1.79 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1224 vapier 1.41 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1225 vapier 1.171 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1226 solar 1.181 case 'D': out = get_endian(elf); break;
1227 vapier 1.206 case 'O': out = strfileperms(elf->filename); break;
1228 vapier 1.72 case 'n':
1229     case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1230 vapier 1.41 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1231 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1232 vapier 1.84 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1233 vapier 1.72 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1234 solar 1.124 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1235 vapier 1.166 case 'a': out = get_elfemtype(elf); break;
1236 solar 1.191 case 'I': out = get_elfosabi(elf); break;
1237     case 'Y': out = get_elf_eabi(elf); break;
1238 vapier 1.193 case 'Z': snprintf(ubuf, sizeof(ubuf), "%lu", (unsigned long)elf->len); out = ubuf; break;;
1239 vapier 1.76 default: warnf("'%c' has no scan code?", out_format[i]);
1240 vapier 1.29 }
1241 vapier 1.95 if (out) {
1242     /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1243     if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1244     xstrncat(&out_buffer, out, &out_len, (tmp-out));
1245     else
1246     xstrcat(&out_buffer, out, &out_len);
1247     }
1248 vapier 1.39 }
1249    
1250 vapier 1.54 #define FOUND_SOMETHING() \
1251 solar 1.73 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1252 vapier 1.76 found_rpath || found_needed || found_interp || found_bind || \
1253 solar 1.124 found_soname || found_sym || found_lib || found_textrels || found_section )
1254 vapier 1.54
1255     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1256     xchrcat(&out_buffer, ' ', &out_len);
1257 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1258 vapier 1.27 }
1259 vapier 1.79 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1260 vapier 1.41 puts(out_buffer);
1261 vapier 1.79 fflush(stdout);
1262     }
1263 vapier 1.10
1264 vapier 1.105 return 0;
1265     }
1266    
1267 vapier 1.106 /* scan a single elf */
1268     static int scanelf_elf(const char *filename, int fd, size_t len)
1269     {
1270 solar 1.120 int ret = 1;
1271 vapier 1.106 elfobj *elf;
1272    
1273     /* verify this is real ELF */
1274     if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1275     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1276 solar 1.120 return ret;
1277     }
1278     switch (match_bits) {
1279     case 32:
1280     if (elf->elf_class != ELFCLASS32)
1281     goto label_done;
1282     break;
1283     case 64:
1284     if (elf->elf_class != ELFCLASS64)
1285     goto label_done;
1286     break;
1287     default: break;
1288 vapier 1.106 }
1289 solar 1.119 if (strlen(match_etypes)) {
1290     char sbuf[126];
1291     strncpy(sbuf, match_etypes, sizeof(sbuf));
1292     if (strchr(match_etypes, ',') != NULL) {
1293     char *p;
1294 vapier 1.186 while ((p = strrchr(sbuf, ',')) != NULL) {
1295 solar 1.119 *p = 0;
1296 solar 1.129 if (etype_lookup(p+1) == get_etype(elf))
1297 solar 1.119 goto label_ret;
1298     }
1299     }
1300 solar 1.129 if (etype_lookup(sbuf) != get_etype(elf))
1301 solar 1.119 goto label_done;
1302     }
1303    
1304     label_ret:
1305 vapier 1.106 ret = scanelf_elfobj(elf);
1306 solar 1.119
1307     label_done:
1308 vapier 1.106 unreadelf(elf);
1309     return ret;
1310     }
1311 solar 1.119
1312 vapier 1.105 /* scan an archive of elfs */
1313 vapier 1.106 static int scanelf_archive(const char *filename, int fd, size_t len)
1314 vapier 1.105 {
1315 vapier 1.106 archive_handle *ar;
1316 vapier 1.105 archive_member *m;
1317 vapier 1.106 char *ar_buffer;
1318     elfobj *elf;
1319    
1320     ar = ar_open_fd(filename, fd);
1321     if (ar == NULL)
1322     return 1;
1323    
1324 vapier 1.201 ar_buffer = mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1325 vapier 1.106 while ((m=ar_next(ar)) != NULL) {
1326     elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1327     if (elf) {
1328     scanelf_elfobj(elf);
1329     unreadelf(elf);
1330     }
1331     }
1332     munmap(ar_buffer, len);
1333    
1334 vapier 1.105 return 0;
1335     }
1336     /* scan a file which may be an elf or an archive or some other magical beast */
1337 solar 1.164 static int scanelf_file(const char *filename, const struct stat *st_cache)
1338 vapier 1.105 {
1339 vapier 1.161 const struct stat *st = st_cache;
1340     struct stat symlink_st;
1341 vapier 1.106 int fd;
1342 vapier 1.105
1343     /* always handle regular files and handle symlinked files if no -y */
1344 vapier 1.161 if (S_ISLNK(st->st_mode)) {
1345 solar 1.164 if (!scan_symlink) return 1;
1346 vapier 1.161 stat(filename, &symlink_st);
1347     st = &symlink_st;
1348 vapier 1.105 }
1349 vapier 1.161
1350     if (!S_ISREG(st->st_mode)) {
1351 vapier 1.105 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1352 solar 1.164 return 1;
1353 vapier 1.105 }
1354    
1355 solar 1.180 if (match_perms) {
1356     if ((st->st_mode | match_perms) != st->st_mode)
1357     return 1;
1358     }
1359 vapier 1.106 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1360 solar 1.164 return 1;
1361 vapier 1.106
1362 vapier 1.161 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1363 vapier 1.105 /* if it isn't an ELF, maybe it's an .a archive */
1364 vapier 1.161 scanelf_archive(filename, fd, st->st_size);
1365 vapier 1.106
1366     close(fd);
1367 solar 1.164 return 0;
1368 solar 1.6 }
1369    
1370 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
1371 solar 1.164 static int scanelf_dir(const char *path)
1372 solar 1.1 {
1373 vapier 1.10 register DIR *dir;
1374     register struct dirent *dentry;
1375 vapier 1.14 struct stat st_top, st;
1376 vapier 1.104 char buf[__PAX_UTILS_PATH_MAX];
1377 vapier 1.32 size_t pathlen = 0, len = 0;
1378 solar 1.164 int ret = 0;
1379 vapier 1.10
1380     /* make sure path exists */
1381 vapier 1.39 if (lstat(path, &st_top) == -1) {
1382     if (be_verbose > 2) printf("%s: does not exist\n", path);
1383 solar 1.164 return 1;
1384 vapier 1.39 }
1385 solar 1.11
1386 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
1387 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
1388 solar 1.164 return scanelf_file(path, &st_top);
1389 vapier 1.10 }
1390    
1391     /* now scan the dir looking for fun stuff */
1392     if ((dir = opendir(path)) == NULL) {
1393     warnf("could not opendir %s: %s", path, strerror(errno));
1394 solar 1.164 return 1;
1395 vapier 1.10 }
1396 vapier 1.114 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1397 solar 1.11
1398 vapier 1.32 pathlen = strlen(path);
1399 vapier 1.10 while ((dentry = readdir(dir))) {
1400     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1401     continue;
1402 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
1403     if (len >= sizeof(buf)) {
1404 vapier 1.76 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1405     (unsigned long)len, (unsigned long)sizeof(buf));
1406 vapier 1.32 continue;
1407     }
1408 solar 1.143 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1409 solar 1.20 if (lstat(buf, &st) != -1) {
1410 vapier 1.10 if (S_ISREG(st.st_mode))
1411 solar 1.164 ret = scanelf_file(buf, &st);
1412 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1413 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1414 solar 1.164 ret = scanelf_dir(buf);
1415 vapier 1.10 }
1416     }
1417     }
1418     closedir(dir);
1419 solar 1.164 return ret;
1420 solar 1.1 }
1421    
1422 vapier 1.133 static int scanelf_from_file(const char *filename)
1423 vapier 1.47 {
1424 solar 1.45 FILE *fp = NULL;
1425     char *p;
1426 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1427 solar 1.164 int ret = 0;
1428 solar 1.45
1429 solar 1.132 if (strcmp(filename, "-") == 0)
1430 solar 1.45 fp = stdin;
1431     else if ((fp = fopen(filename, "r")) == NULL)
1432     return 1;
1433    
1434 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1435 solar 1.45 if ((p = strchr(path, '\n')) != NULL)
1436     *p = 0;
1437 vapier 1.66 search_path = path;
1438 solar 1.164 ret = scanelf_dir(path);
1439 solar 1.45 }
1440     if (fp != stdin)
1441     fclose(fp);
1442 solar 1.164 return ret;
1443 solar 1.45 }
1444    
1445 solar 1.154 #if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1446 vapier 1.148
1447     static int load_ld_cache_config(int i, const char *fname)
1448 vapier 1.48 {
1449     FILE *fp = NULL;
1450     char *p;
1451 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1452 vapier 1.48
1453 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1454 solar 1.123 return i;
1455    
1456     if ((fp = fopen(fname, "r")) == NULL)
1457     return i;
1458 vapier 1.48
1459 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1460 vapier 1.48 if ((p = strrchr(path, '\r')) != NULL)
1461     *p = 0;
1462     if ((p = strchr(path, '\n')) != NULL)
1463     *p = 0;
1464 solar 1.154 #ifdef __linux__
1465 vapier 1.186 /* recursive includes of the same file will make this segfault. */
1466 solar 1.129 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1467 solar 1.123 glob64_t gl;
1468     size_t x;
1469     char gpath[__PAX_UTILS_PATH_MAX];
1470    
1471 solar 1.129 memset(gpath, 0, sizeof(gpath));
1472 solar 1.123
1473     if (path[8] != '/')
1474 solar 1.129 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1475 solar 1.123 else
1476 solar 1.129 strncpy(gpath, &path[8], sizeof(gpath));
1477 solar 1.123
1478     if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1479     for (x = 0; x < gl.gl_pathc; ++x) {
1480     /* try to avoid direct loops */
1481     if (strcmp(gl.gl_pathv[x], fname) == 0)
1482     continue;
1483 vapier 1.148 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1484 vapier 1.149 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1485 solar 1.123 globfree64(&gl);
1486     return i;
1487     }
1488     }
1489     globfree64 (&gl);
1490     continue;
1491 solar 1.160 }
1492 solar 1.123 }
1493 solar 1.154 #endif
1494 solar 1.123 if (*path != '/')
1495     continue;
1496 vapier 1.48
1497     ldpaths[i++] = xstrdup(path);
1498    
1499 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1500 vapier 1.48 break;
1501     }
1502     ldpaths[i] = NULL;
1503    
1504     fclose(fp);
1505 solar 1.123 return i;
1506 vapier 1.48 }
1507 flameeyes 1.141
1508 vapier 1.148 #elif defined(__FreeBSD__) || (__DragonFly__)
1509    
1510     static int load_ld_cache_config(int i, const char *fname)
1511 flameeyes 1.141 {
1512     FILE *fp = NULL;
1513     char *b = NULL, *p;
1514     struct elfhints_hdr hdr;
1515 vapier 1.152
1516 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1517 flameeyes 1.141 return i;
1518    
1519     if ((fp = fopen(fname, "r")) == NULL)
1520     return i;
1521    
1522 vapier 1.152 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1523     hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1524     fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1525     {
1526 flameeyes 1.141 fclose(fp);
1527     return i;
1528     }
1529 vapier 1.152
1530 vapier 1.186 b = xmalloc(hdr.dirlistlen + 1);
1531 vapier 1.152 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1532 flameeyes 1.141 fclose(fp);
1533     free(b);
1534     return i;
1535     }
1536 vapier 1.152
1537     while ((p = strsep(&b, ":"))) {
1538     if (*p == '\0') continue;
1539 flameeyes 1.141 ldpaths[i++] = xstrdup(p);
1540 vapier 1.152
1541 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1542 flameeyes 1.141 break;
1543     }
1544     ldpaths[i] = NULL;
1545 vapier 1.157
1546 flameeyes 1.141 free(b);
1547     fclose(fp);
1548     return i;
1549     }
1550 vapier 1.148
1551     #else
1552 vapier 1.192 #ifdef __ELF__
1553 vapier 1.148 #warning Cache config support not implemented for your target
1554 vapier 1.192 #endif
1555 vapier 1.148 static int load_ld_cache_config(int i, const char *fname)
1556     {
1557     memset(ldpaths, 0x00, sizeof(ldpaths));
1558 vapier 1.192 return 0;
1559 vapier 1.148 }
1560 flameeyes 1.141 #endif
1561 vapier 1.48
1562 vapier 1.10 /* scan /etc/ld.so.conf for paths */
1563 vapier 1.184 static void scanelf_ldpath(void)
1564 vapier 1.10 {
1565 vapier 1.17 char scan_l, scan_ul, scan_ull;
1566 vapier 1.48 int i = 0;
1567 vapier 1.10
1568 vapier 1.48 if (!ldpaths[0])
1569     err("Unable to load any paths from ld.so.conf");
1570 vapier 1.10
1571 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
1572    
1573 vapier 1.48 while (ldpaths[i]) {
1574     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
1575     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
1576     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
1577     scanelf_dir(ldpaths[i]);
1578     ++i;
1579     }
1580 vapier 1.10
1581 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
1582     if (!scan_ul) scanelf_dir("/usr/lib");
1583     if (!scan_ull) scanelf_dir("/usr/local/lib");
1584 vapier 1.10 }
1585 solar 1.1
1586 vapier 1.10 /* scan env PATH for paths */
1587 vapier 1.184 static void scanelf_envpath(void)
1588 solar 1.1 {
1589 solar 1.34 char *path, *p;
1590 vapier 1.10
1591     path = getenv("PATH");
1592     if (!path)
1593     err("PATH is not set in your env !");
1594 vapier 1.41 path = xstrdup(path);
1595 vapier 1.10
1596     while ((p = strrchr(path, ':')) != NULL) {
1597     scanelf_dir(p + 1);
1598     *p = 0;
1599     }
1600 vapier 1.17
1601 solar 1.34 free(path);
1602 solar 1.1 }
1603    
1604 solar 1.191 /* usage / invocation handling functions */ /* Free Flags: c d j u w C G H J K P Q U W */
1605     #define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DIYO:ZBhV"
1606 vapier 1.27 #define a_argument required_argument
1607 vapier 1.10 static struct option const long_opts[] = {
1608     {"path", no_argument, NULL, 'p'},
1609     {"ldpath", no_argument, NULL, 'l'},
1610     {"recursive", no_argument, NULL, 'R'},
1611 vapier 1.14 {"mount", no_argument, NULL, 'm'},
1612 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
1613 vapier 1.105 {"archives", no_argument, NULL, 'A'},
1614     {"ldcache", no_argument, NULL, 'L'},
1615 vapier 1.101 {"fix", no_argument, NULL, 'X'},
1616 solar 1.127 {"setpax", a_argument, NULL, 'z'},
1617 vapier 1.10 {"pax", no_argument, NULL, 'x'},
1618 solar 1.16 {"header", no_argument, NULL, 'e'},
1619 vapier 1.10 {"textrel", no_argument, NULL, 't'},
1620     {"rpath", no_argument, NULL, 'r'},
1621 vapier 1.32 {"needed", no_argument, NULL, 'n'},
1622 vapier 1.38 {"interp", no_argument, NULL, 'i'},
1623 vapier 1.49 {"bind", no_argument, NULL, 'b'},
1624 vapier 1.84 {"soname", no_argument, NULL, 'S'},
1625 vapier 1.76 {"symbol", a_argument, NULL, 's'},
1626 solar 1.124 {"section", a_argument, NULL, 'k'},
1627 vapier 1.76 {"lib", a_argument, NULL, 'N'},
1628 solar 1.86 {"gmatch", no_argument, NULL, 'g'},
1629 vapier 1.76 {"textrels", no_argument, NULL, 'T'},
1630 solar 1.119 {"etype", a_argument, NULL, 'E'},
1631 solar 1.120 {"bits", a_argument, NULL, 'M'},
1632 solar 1.181 {"endian", no_argument, NULL, 'D'},
1633 solar 1.191 {"osabi", no_argument, NULL, 'I'},
1634     {"eabi", no_argument, NULL, 'Y'},
1635 solar 1.180 {"perms", a_argument, NULL, 'O'},
1636 solar 1.190 {"size", no_argument, NULL, 'Z'},
1637 vapier 1.10 {"all", no_argument, NULL, 'a'},
1638     {"quiet", no_argument, NULL, 'q'},
1639 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
1640 vapier 1.76 {"format", a_argument, NULL, 'F'},
1641     {"from", a_argument, NULL, 'f'},
1642     {"file", a_argument, NULL, 'o'},
1643 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
1644 vapier 1.10 {"help", no_argument, NULL, 'h'},
1645     {"version", no_argument, NULL, 'V'},
1646     {NULL, no_argument, NULL, 0x0}
1647     };
1648 solar 1.57
1649 solar 1.68 static const char *opts_help[] = {
1650 vapier 1.10 "Scan all directories in PATH environment",
1651     "Scan all directories in /etc/ld.so.conf",
1652 vapier 1.14 "Scan directories recursively",
1653 vapier 1.37 "Don't recursively cross mount points",
1654 vapier 1.101 "Don't scan symlinks",
1655 vapier 1.105 "Scan archives (.a files)",
1656     "Utilize ld.so.cache information (use with -r/-n)",
1657 solar 1.127 "Try and 'fix' bad things (use with -r/-e)",
1658     "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1659 vapier 1.10 "Print PaX markings",
1660 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
1661 vapier 1.10 "Print TEXTREL information",
1662     "Print RPATH information",
1663 vapier 1.32 "Print NEEDED information",
1664 vapier 1.38 "Print INTERP information",
1665 vapier 1.49 "Print BIND information",
1666 vapier 1.84 "Print SONAME information",
1667 vapier 1.27 "Find a specified symbol",
1668 solar 1.124 "Find a specified section",
1669 vapier 1.72 "Find a specified library",
1670 solar 1.86 "Use strncmp to match libraries. (use with -N)",
1671 vapier 1.76 "Locate cause of TEXTREL",
1672 solar 1.129 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1673 solar 1.120 "Print only ELF files matching numeric bits",
1674 solar 1.181 "Print Endianness",
1675 solar 1.191 "Print OSABI",
1676     "Print EABI (EM_ARM Only)",
1677 solar 1.180 "Print only ELF files matching octal permissions",
1678 solar 1.190 "Print ELF file size",
1679 vapier 1.82 "Print all scanned info (-x -e -t -r -b)\n",
1680 vapier 1.14 "Only output 'bad' things",
1681     "Be verbose (can be specified more than once)",
1682 vapier 1.39 "Use specified format for output",
1683 solar 1.45 "Read input stream from a filename",
1684 vapier 1.24 "Write output stream to a filename",
1685 vapier 1.14 "Don't display the header",
1686 vapier 1.10 "Print this help and exit",
1687     "Print version and exit",
1688     NULL
1689     };
1690    
1691     /* display usage and exit */
1692     static void usage(int status)
1693 solar 1.1 {
1694 vapier 1.44 unsigned long i;
1695 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
1696 vapier 1.105 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1697 solar 1.35 printf("Options: -[%s]\n", PARSE_FLAGS);
1698 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
1699 vapier 1.27 if (long_opts[i].has_arg == no_argument)
1700 vapier 1.157 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1701 vapier 1.27 long_opts[i].name, opts_help[i]);
1702     else
1703 solar 1.124 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1704 vapier 1.27 long_opts[i].name, opts_help[i]);
1705 solar 1.45
1706 vapier 1.173 puts("\nFor more information, see the scanelf(1) manpage");
1707 vapier 1.10 exit(status);
1708 solar 1.1 }
1709    
1710     /* parse command line arguments and preform needed actions */
1711 vapier 1.165 #define do_pax_state(option, flag) \
1712     if (islower(option)) { \
1713     flags &= ~PF_##flag; \
1714     flags |= PF_NO##flag; \
1715     } else { \
1716     flags &= ~PF_NO##flag; \
1717     flags |= PF_##flag; \
1718     }
1719 solar 1.164 static int parseargs(int argc, char *argv[])
1720 vapier 1.10 {
1721 vapier 1.48 int i;
1722 vapier 1.133 const char *from_file = NULL;
1723 solar 1.164 int ret = 0;
1724 vapier 1.10
1725     opterr = 0;
1726 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1727     switch (i) {
1728 vapier 1.10
1729 vapier 1.39 case 'V':
1730 vapier 1.80 printf("pax-utils-%s: %s compiled %s\n%s\n"
1731     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1732     VERSION, __FILE__, __DATE__, rcsid, argv0);
1733 vapier 1.10 exit(EXIT_SUCCESS);
1734     break;
1735     case 'h': usage(EXIT_SUCCESS); break;
1736 solar 1.45 case 'f':
1737 vapier 1.100 if (from_file) warn("You prob don't want to specify -f twice");
1738     from_file = optarg;
1739 solar 1.45 break;
1740 solar 1.119 case 'E':
1741     strncpy(match_etypes, optarg, sizeof(match_etypes));
1742     break;
1743 solar 1.120 case 'M':
1744     match_bits = atoi(optarg);
1745 solar 1.182 if (match_bits == 0) {
1746     if (strcmp(optarg, "ELFCLASS32") == 0)
1747     match_bits = 32;
1748     if (strcmp(optarg, "ELFCLASS64") == 0)
1749     match_bits = 64;
1750     }
1751 solar 1.120 break;
1752 solar 1.180 case 'O':
1753 vapier 1.205 if (sscanf(optarg, "%o", &match_perms) == -1)
1754 solar 1.180 match_bits = 0;
1755     break;
1756 vapier 1.24 case 'o': {
1757 vapier 1.146 if (freopen(optarg, "w", stdout) == NULL)
1758 vapier 1.24 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1759 solar 1.21 break;
1760     }
1761 solar 1.124 case 'k':
1762 vapier 1.126 if (find_section) warn("You prob don't want to specify -k twice");
1763 solar 1.124 find_section = optarg;
1764     break;
1765 vapier 1.39 case 's': {
1766 vapier 1.93 if (find_sym) warn("You prob don't want to specify -s twice");
1767     find_sym = optarg;
1768 vapier 1.39 break;
1769     }
1770 vapier 1.72 case 'N': {
1771 vapier 1.93 if (find_lib) warn("You prob don't want to specify -N twice");
1772     find_lib = optarg;
1773 vapier 1.72 break;
1774     }
1775 vapier 1.39
1776     case 'F': {
1777 vapier 1.93 if (out_format) warn("You prob don't want to specify -F twice");
1778     out_format = optarg;
1779 vapier 1.39 break;
1780     }
1781 solar 1.127 case 'z': {
1782 solar 1.129 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1783 solar 1.127 size_t x;
1784 vapier 1.27
1785 vapier 1.186 for (x = 0; x < strlen(optarg); x++) {
1786     switch (optarg[x]) {
1787 solar 1.127 case 'p':
1788     case 'P':
1789 vapier 1.165 do_pax_state(optarg[x], PAGEEXEC);
1790 solar 1.127 break;
1791     case 's':
1792     case 'S':
1793 vapier 1.165 do_pax_state(optarg[x], SEGMEXEC);
1794 solar 1.127 break;
1795     case 'm':
1796     case 'M':
1797 vapier 1.165 do_pax_state(optarg[x], MPROTECT);
1798 solar 1.127 break;
1799     case 'e':
1800     case 'E':
1801 vapier 1.165 do_pax_state(optarg[x], EMUTRAMP);
1802 solar 1.127 break;
1803     case 'r':
1804     case 'R':
1805 vapier 1.165 do_pax_state(optarg[x], RANDMMAP);
1806 solar 1.127 break;
1807     case 'x':
1808     case 'X':
1809 vapier 1.165 do_pax_state(optarg[x], RANDEXEC);
1810 solar 1.127 break;
1811     default:
1812     break;
1813     }
1814     }
1815     if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1816     ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1817     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1818     ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1819     ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1820     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1821     setpax = flags;
1822     break;
1823     }
1824 solar 1.190 case 'Z': show_size = 1; break;
1825 solar 1.176 case 'g': g_match = 1; break;
1826 vapier 1.102 case 'L': use_ldcache = 1; break;
1827 vapier 1.37 case 'y': scan_symlink = 0; break;
1828 vapier 1.105 case 'A': scan_archives = 1; break;
1829 solar 1.16 case 'B': show_banner = 0; break;
1830 vapier 1.10 case 'l': scan_ldpath = 1; break;
1831     case 'p': scan_envpath = 1; break;
1832     case 'R': dir_recurse = 1; break;
1833 vapier 1.14 case 'm': dir_crossmount = 0; break;
1834 vapier 1.101 case 'X': ++fix_elf; break;
1835 vapier 1.10 case 'x': show_pax = 1; break;
1836 solar 1.73 case 'e': show_phdr = 1; break;
1837 vapier 1.10 case 't': show_textrel = 1; break;
1838     case 'r': show_rpath = 1; break;
1839 vapier 1.32 case 'n': show_needed = 1; break;
1840 vapier 1.38 case 'i': show_interp = 1; break;
1841 vapier 1.49 case 'b': show_bind = 1; break;
1842 vapier 1.84 case 'S': show_soname = 1; break;
1843 vapier 1.76 case 'T': show_textrels = 1; break;
1844 vapier 1.10 case 'q': be_quiet = 1; break;
1845 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1846 solar 1.183 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
1847 solar 1.181 case 'D': show_endian = 1; break;
1848 solar 1.191 case 'I': show_osabi = 1; break;
1849     case 'Y': show_eabi = 1; break;
1850 vapier 1.10 case ':':
1851 vapier 1.113 err("Option '%c' is missing parameter", optopt);
1852 vapier 1.10 case '?':
1853 solar 1.119 err("Unknown option '%c' or argument missing", optopt);
1854 vapier 1.10 default:
1855 vapier 1.113 err("Unhandled option '%c'; please report this", i);
1856 vapier 1.10 }
1857     }
1858 solar 1.170 if (show_textrels && be_verbose) {
1859     if (which("objdump") != NULL)
1860     has_objdump = 1;
1861     }
1862 vapier 1.39 /* let the format option override all other options */
1863     if (out_format) {
1864 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1865 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
1866 solar 1.191 show_textrels = show_perms = show_endian = show_size = \
1867     show_osabi = show_eabi = 0;
1868 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1869 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1870 vapier 1.39
1871 vapier 1.48 switch (out_format[++i]) {
1872 solar 1.132 case '+': break;
1873 vapier 1.39 case '%': break;
1874 vapier 1.70 case '#': break;
1875 vapier 1.39 case 'F': break;
1876 vapier 1.66 case 'p': break;
1877     case 'f': break;
1878 solar 1.124 case 'k': break;
1879 vapier 1.39 case 's': break;
1880 vapier 1.72 case 'N': break;
1881 vapier 1.41 case 'o': break;
1882 vapier 1.166 case 'a': break;
1883 vapier 1.171 case 'M': break;
1884 solar 1.190 case 'Z': show_size = 1; break;
1885 solar 1.181 case 'D': show_endian = 1; break;
1886 solar 1.191 case 'I': show_osabi = 1; break;
1887     case 'Y': show_eabi = 1; break;
1888 solar 1.180 case 'O': show_perms = 1; break;
1889 vapier 1.39 case 'x': show_pax = 1; break;
1890 solar 1.73 case 'e': show_phdr = 1; break;
1891 vapier 1.39 case 't': show_textrel = 1; break;
1892     case 'r': show_rpath = 1; break;
1893     case 'n': show_needed = 1; break;
1894     case 'i': show_interp = 1; break;
1895 vapier 1.49 case 'b': show_bind = 1; break;
1896 vapier 1.84 case 'S': show_soname = 1; break;
1897 vapier 1.76 case 'T': show_textrels = 1; break;
1898 vapier 1.39 default:
1899 vapier 1.162 err("Invalid format specifier '%c' (byte %i)",
1900 vapier 1.48 out_format[i], i+1);
1901 vapier 1.39 }
1902     }
1903 vapier 1.41
1904     /* construct our default format */
1905     } else {
1906     size_t fmt_len = 30;
1907 vapier 1.186 out_format = xmalloc(sizeof(char) * fmt_len);
1908 vapier 1.194 *out_format = '\0';
1909 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1910     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1911 solar 1.180 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
1912 solar 1.190 if (show_size) xstrcat(&out_format, "%Z ", &fmt_len);
1913 solar 1.181 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
1914 solar 1.191 if (show_osabi) xstrcat(&out_format, "%I ", &fmt_len);
1915     if (show_eabi) xstrcat(&out_format, "%Y ", &fmt_len);
1916 vapier 1.76 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1917     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1918     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1919     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1920     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1921     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1922 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1923 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1924     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1925 solar 1.124 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1926 vapier 1.76 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1927     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1928 vapier 1.39 }
1929 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1930 vapier 1.39
1931     /* now lets actually do the scanning */
1932 vapier 1.102 if (scan_ldpath || use_ldcache)
1933 vapier 1.148 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1934 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1935     if (scan_envpath) scanelf_envpath();
1936 solar 1.153 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1937 vapier 1.133 from_file = "-";
1938 solar 1.45 if (from_file) {
1939     scanelf_from_file(from_file);
1940     from_file = *argv;
1941     }
1942     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1943 vapier 1.25 err("Nothing to scan !?");
1944 vapier 1.66 while (optind < argc) {
1945     search_path = argv[optind++];
1946 solar 1.164 ret = scanelf_dir(search_path);
1947 vapier 1.66 }
1948 vapier 1.27
1949 vapier 1.39 /* clean up */
1950 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1951     free(ldpaths[i]);
1952 solar 1.96
1953     if (ldcache != 0)
1954     munmap(ldcache, ldcache_size);
1955 solar 1.164 return ret;
1956 vapier 1.10 }
1957    
1958 vapier 1.150 static char **get_split_env(const char *envvar)
1959     {
1960 vapier 1.152 const char *delims = " \t\n";
1961 solar 1.143 char **envvals = NULL;
1962 vapier 1.152 char *env, *s;
1963 kevquinn 1.142 int nentry;
1964    
1965 solar 1.143 if ((env = getenv(envvar)) == NULL)
1966     return NULL;
1967 kevquinn 1.142
1968 solar 1.143 env = xstrdup(env);
1969     if (env == NULL)
1970     return NULL;
1971 kevquinn 1.142
1972 vapier 1.152 s = strtok(env, delims);
1973     if (s == NULL) {
1974     free(env);
1975     return NULL;
1976     }
1977    
1978 solar 1.143 nentry = 0;
1979 vapier 1.152 while (s != NULL) {
1980     ++nentry;
1981     envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1982     envvals[nentry-1] = s;
1983     s = strtok(NULL, delims);
1984 kevquinn 1.142 }
1985 vapier 1.152 envvals[nentry] = NULL;
1986 kevquinn 1.142
1987 vapier 1.152 /* don't want to free(env) as it contains the memory that backs
1988     * the envvals array of strings */
1989 kevquinn 1.142 return envvals;
1990     }
1991 solar 1.181
1992 vapier 1.184 static void parseenv(void)
1993 vapier 1.150 {
1994     qa_textrels = get_split_env("QA_TEXTRELS");
1995     qa_execstack = get_split_env("QA_EXECSTACK");
1996     qa_wx_load = get_split_env("QA_WX_LOAD");
1997 vapier 1.41 }
1998 solar 1.163
1999 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
2000 vapier 1.184 static void cleanup(void)
2001 vapier 1.152 {
2002     free(out_format);
2003     free(qa_textrels);
2004     free(qa_execstack);
2005     free(qa_wx_load);
2006     }
2007     #endif
2008 vapier 1.41
2009 vapier 1.10 int main(int argc, char *argv[])
2010 solar 1.1 {
2011 solar 1.164 int ret;
2012 vapier 1.10 if (argc < 2)
2013     usage(EXIT_FAILURE);
2014 kevquinn 1.142 parseenv();
2015 solar 1.164 ret = parseargs(argc, argv);
2016 solar 1.21 fclose(stdout);
2017 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
2018     cleanup();
2019     warn("The calls to add/delete heap should be off:\n"
2020     "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
2021     "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
2022 solar 1.61 #endif
2023 solar 1.164 return ret;
2024 solar 1.1 }
2025 vapier 1.155
2026     /* Match filename against entries in matchlist, return TRUE
2027     * if the file is listed */
2028     static int file_matches_list(const char *filename, char **matchlist)
2029     {
2030     char **file;
2031     char *match;
2032     char buf[__PAX_UTILS_PATH_MAX];
2033    
2034     if (matchlist == NULL)
2035     return 0;
2036    
2037     for (file = matchlist; *file != NULL; file++) {
2038     if (search_path) {
2039     snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2040     match = buf;
2041     } else {
2042     match = *file;
2043     }
2044     if (fnmatch(match, filename, 0) == 0)
2045     return 1;
2046     }
2047     return 0;
2048     }

  ViewVC Help
Powered by ViewVC 1.1.20