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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.107 - (hide annotations) (download) (as text)
Wed Jan 18 22:28:46 2006 UTC (8 years, 6 months ago) by solar
Branch: MAIN
Changes since 1.106: +3 -3 lines
File MIME type: text/x-csrc
- dont write to memory when NULL rpaths exists and not using -X/--fix

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

  ViewVC Help
Powered by ViewVC 1.1.20