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

Diff of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.43 Revision 1.93
1/* 1/*
2 * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 * Copyright 1999-2005 Gentoo Foundation 2 * Copyright 2003-2005 Gentoo Foundation
4 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.93 2005/12/10 04:07:55 vapier Exp $
6 * 5 *
7 ******************************************************************** 6 * Copyright 2003-2005 Ned Ludd - <solar@gentoo.org>
8 * This program is free software; you can redistribute it and/or 7 * Copyright 2004-2005 Mike Frysinger - <vapier@gentoo.org>
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21 * MA 02111-1307, USA.
22 */ 8 */
23 9
24#include <stdio.h> 10#include <stdio.h>
25#include <stdlib.h> 11#include <stdlib.h>
26#include <sys/types.h> 12#include <sys/types.h>
27#define __USE_GNU 13#include <libgen.h>
14#include <limits.h>
28#include <string.h> 15#include <string.h>
29#include <errno.h> 16#include <errno.h>
30#include <unistd.h> 17#include <unistd.h>
31#include <sys/stat.h> 18#include <sys/stat.h>
32#include <dirent.h> 19#include <dirent.h>
33#include <getopt.h> 20#include <getopt.h>
34#include <assert.h> 21#include <assert.h>
35
36#include "paxelf.h" 22#include "paxinc.h"
37 23
38static const char *rcsid = "$Id: scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $"; 24static const char *rcsid = "$Id: scanelf.c,v 1.93 2005/12/10 04:07:55 vapier Exp $";
39#define argv0 "scanelf" 25#define argv0 "scanelf"
26
27#define IS_MODIFIER(c) (c == '%' || c == '#')
40 28
41 29
42 30
43/* prototypes */ 31/* prototypes */
44static void scanelf_file(const char *filename); 32static void scanelf_file(const char *filename);
45static void scanelf_dir(const char *path); 33static void scanelf_dir(const char *path);
46static void scanelf_ldpath(); 34static void scanelf_ldpath();
47static void scanelf_envpath(); 35static void scanelf_envpath();
48static void usage(int status); 36static void usage(int status);
49static void parseargs(int argc, char *argv[]); 37static void parseargs(int argc, char *argv[]);
50static char *xstrdup(char *s); 38static char *xstrdup(const char *s);
51static void *xmalloc(size_t size); 39static void *xmalloc(size_t size);
52static void xstrcat(char **dst, const char *src, size_t *curr_len); 40static void xstrcat(char **dst, const char *src, size_t *curr_len);
53static inline void xchrcat(char **dst, const char append, size_t *curr_len); 41static inline void xchrcat(char **dst, const char append, size_t *curr_len);
54static int xemptybuffer(const char *buff);
55 42
56/* variables to control behavior */ 43/* variables to control behavior */
44static char *ldpaths[256];
57static char scan_ldpath = 0; 45static char scan_ldpath = 0;
58static char scan_envpath = 0; 46static char scan_envpath = 0;
59static char scan_symlink = 1; 47static char scan_symlink = 1;
60static char dir_recurse = 0; 48static char dir_recurse = 0;
61static char dir_crossmount = 1; 49static char dir_crossmount = 1;
62static char show_pax = 0; 50static char show_pax = 0;
63static char show_stack = 0; 51static char show_phdr = 0;
64static char show_textrel = 0; 52static char show_textrel = 0;
65static char show_rpath = 0; 53static char show_rpath = 0;
66static char show_needed = 0; 54static char show_needed = 0;
67static char show_interp = 0; 55static char show_interp = 0;
56static char show_bind = 0;
57static char show_soname = 0;
58static char show_textrels = 0;
68static char show_banner = 1; 59static char show_banner = 1;
69static char be_quiet = 0; 60static char be_quiet = 0;
70static char be_verbose = 0; 61static char be_verbose = 0;
62static char be_wewy_wewy_quiet = 0;
71static char *find_sym = NULL, *versioned_symname = NULL; 63static char *find_sym = NULL, *versioned_symname = NULL;
64static char *find_lib = NULL;
72static char *out_format = NULL; 65static char *out_format = NULL;
73 66static char *search_path = NULL;
67static char gmatch = 0;
74 68
75 69
76/* sub-funcs for scanelf_file() */ 70/* sub-funcs for scanelf_file() */
71static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
72{
73 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
74#define GET_SYMTABS(B) \
75 if (elf->elf_class == ELFCLASS ## B) { \
76 Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
77 /* debug sections */ \
78 symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
79 strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
80 /* runtime sections */ \
81 dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
82 dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
83 if (symtab && dynsym) { \
84 *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
85 } else { \
86 *sym = (void*)(symtab ? symtab : dynsym); \
87 } \
88 if (strtab && dynstr) { \
89 *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
90 } else { \
91 *tab = (void*)(strtab ? strtab : dynstr); \
92 } \
93 }
94 GET_SYMTABS(32)
95 GET_SYMTABS(64)
96}
77static char *scanelf_file_pax(elfobj *elf, char *found_pax) 97static char *scanelf_file_pax(elfobj *elf, char *found_pax)
78{ 98{
79 static char *paxflags; 99 static char ret[7];
100 unsigned long i, shown;
80 101
81 if (!show_pax) return NULL; 102 if (!show_pax) return NULL;
82 103
83 paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
84 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
85 *found_pax = 1;
86 return paxflags;
87 }
88
89 return NULL;
90}
91static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
92{
93 static char ret[8];
94 char *found;
95 int i, off, shown;
96
97 if (!show_stack) return NULL;
98
99 shown = 0; 104 shown = 0;
100 strcpy(ret, "--- ---"); 105 memset(&ret, 0, sizeof(ret));
106
107 if (elf->phdr) {
101#define SHOW_STACK(B) \ 108#define SHOW_PAX(B) \
102 if (elf->elf_class == ELFCLASS ## B) { \ 109 if (elf->elf_class == ELFCLASS ## B) { \
103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 110 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 111 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 112 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
106 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 113 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
107 found = found_stack; \
108 off = 0; \
109 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
110 found = found_relro; \
111 off = 3; \
112 } else \
113 continue; \ 114 continue; \
114 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 115 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
115 continue; \ 116 continue; \
116 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \ 117 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
117 *found = 1; \ 118 *found_pax = 1; \
118 ++shown; \ 119 ++shown; \
120 break; \
119 } \ 121 } \
120 } 122 }
121 SHOW_STACK(32) 123 SHOW_PAX(32)
122 SHOW_STACK(64) 124 SHOW_PAX(64)
123 if (be_quiet && !shown) 125 }
126
127 /* fall back to EI_PAX if no PT_PAX was found */
128 if (!*ret) {
129 static char *paxflags;
130 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
131 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
132 *found_pax = 1;
133 return (be_wewy_wewy_quiet ? NULL : paxflags);
134 }
135 strncpy(ret, paxflags, sizeof(ret));
136 }
137
138 if (be_wewy_wewy_quiet || (be_quiet && !shown))
124 return NULL; 139 return NULL;
125 else 140 else
126 return ret; 141 return ret;
127} 142}
143
144static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
145{
146 static char ret[12];
147 char *found;
148 unsigned long i, shown;
149 unsigned char multi_stack, multi_relro, multi_load;
150
151 if (!show_phdr) return NULL;
152
153 memcpy(ret, "--- --- ---\0", 12);
154
155 shown = 0;
156 multi_stack = multi_relro = multi_load = 0;
157
158#define SHOW_PHDR(B) \
159 if (elf->elf_class == ELFCLASS ## B) { \
160 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
161 Elf ## B ## _Off offset; \
162 uint32_t flags, check_flags; \
163 if (elf->phdr != NULL) { \
164 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
165 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
166 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
167 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
168 found = found_phdr; \
169 offset = 0; \
170 check_flags = PF_X; \
171 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
172 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
173 found = found_relro; \
174 offset = 4; \
175 check_flags = PF_X; \
176 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
177 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \
178 found = found_load; \
179 offset = 8; \
180 check_flags = PF_W|PF_X; \
181 } else \
182 continue; \
183 flags = EGET(phdr[i].p_flags); \
184 if (be_quiet && ((flags & check_flags) != check_flags)) \
185 continue; \
186 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
187 *found = 1; \
188 ++shown; \
189 } \
190 } else if (elf->shdr != NULL) { \
191 /* no program headers which means this is prob an object file */ \
192 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
193 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
194 check_flags = SHF_WRITE|SHF_EXECINSTR; \
195 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
196 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
197 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
198 if (!strcmp((char*)(elf->data + offset), ".note.GNU-stack")) { \
199 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
200 flags = EGET(shdr[i].sh_flags); \
201 if (be_quiet && ((flags & check_flags) != check_flags)) \
202 continue; \
203 ++*found_phdr; \
204 shown = 1; \
205 if (flags & SHF_WRITE) ret[0] = 'W'; \
206 if (flags & SHF_ALLOC) ret[1] = 'A'; \
207 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
208 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
209 break; \
210 } \
211 } \
212 if (!multi_stack) { \
213 *found_phdr = 1; \
214 shown = 1; \
215 memcpy(ret, "!WX", 3); \
216 } \
217 } \
218 }
219 SHOW_PHDR(32)
220 SHOW_PHDR(64)
221
222 if (be_wewy_wewy_quiet || (be_quiet && !shown))
223 return NULL;
224 else
225 return ret;
226}
128static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 227static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
129{ 228{
130 static char *ret = "TEXTREL"; 229 static const char *ret = "TEXTREL";
131 int i; 230 unsigned long i;
132 231
133 if (!show_textrel) return NULL; 232 if (!show_textrel && !show_textrels) return NULL;
134 233
234 if (elf->phdr) {
135#define SHOW_TEXTREL(B) \ 235#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 236 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \ 237 Elf ## B ## _Dyn *dyn; \
138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 238 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 239 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
240 Elf ## B ## _Off offset; \
140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 241 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
141 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 242 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
243 offset = EGET(phdr[i].p_offset); \
244 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 245 dyn = DYN ## B (elf->data + offset); \
143 while (EGET(dyn->d_tag) != DT_NULL) { \ 246 while (EGET(dyn->d_tag) != DT_NULL) { \
144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 247 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
145 *found_textrel = 1; \ 248 *found_textrel = 1; \
146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 249 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \ 250 return (be_wewy_wewy_quiet ? NULL : ret); \
148 } \ 251 } \
149 ++dyn; \ 252 ++dyn; \
150 } \ 253 } \
151 } } 254 } }
152 SHOW_TEXTREL(32) 255 SHOW_TEXTREL(32)
153 SHOW_TEXTREL(64) 256 SHOW_TEXTREL(64)
154 if (be_quiet) 257 }
258
259 if (be_quiet || be_wewy_wewy_quiet)
155 return NULL; 260 return NULL;
156 else 261 else
157 return " - "; 262 return " - ";
158} 263}
264static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
265{
266 unsigned long s, r, rmax;
267 void *symtab_void, *strtab_void, *text_void;
268
269 if (!show_textrels) return NULL;
270
271 /* don't search for TEXTREL's if the ELF doesn't have any */
272 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
273 if (!*found_textrel) return NULL;
274
275 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
276 text_void = elf_findsecbyname(elf, ".text");
277
278 if (symtab_void && strtab_void && text_void && elf->shdr) {
279#define SHOW_TEXTRELS(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
282 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
283 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
284 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
285 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
286 Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
287 uint ## B ## _t memsz = EGET(text->sh_size); \
288 Elf ## B ## _Rel *rel; \
289 Elf ## B ## _Rela *rela; \
290 /* search the section headers for relocations */ \
291 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
292 uint32_t sh_type = EGET(shdr[s].sh_type); \
293 if (sh_type == SHT_REL) { \
294 rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
295 rela = NULL; \
296 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
297 } else if (sh_type == SHT_RELA) { \
298 rel = NULL; \
299 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
300 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
301 } else \
302 continue; \
303 /* now see if any of the relocs are in the .text */ \
304 for (r = 0; r < rmax; ++r) { \
305 unsigned long sym_max; \
306 Elf ## B ## _Addr offset_tmp; \
307 Elf ## B ## _Sym *func; \
308 Elf ## B ## _Sym *sym; \
309 Elf ## B ## _Addr r_offset; \
310 uint ## B ## _t r_info; \
311 if (sh_type == SHT_REL) { \
312 r_offset = EGET(rel[r].r_offset); \
313 r_info = EGET(rel[r].r_info); \
314 } else { \
315 r_offset = EGET(rela[r].r_offset); \
316 r_info = EGET(rela[r].r_info); \
317 } \
318 /* make sure this relocation is inside of the .text */ \
319 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
320 if (be_verbose <= 2) continue; \
321 } else \
322 *found_textrels = 1; \
323 /* locate this relocation symbol name */ \
324 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
325 sym_max = ELF ## B ## _R_SYM(r_info); \
326 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
327 sym += sym_max; \
328 else \
329 sym = NULL; \
330 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
331 /* show the raw details about this reloc */ \
332 printf(" %s: ", elf->base_filename); \
333 if (sym && sym->st_name) \
334 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
335 else \
336 printf("(memory/fake?)"); \
337 printf(" [0x%lX]", (unsigned long)r_offset); \
338 /* now try to find the closest symbol that this rel is probably in */ \
339 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
340 func = NULL; \
341 offset_tmp = 0; \
342 while (sym_max--) { \
343 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
344 func = sym; \
345 offset_tmp = EGET(sym->st_value); \
346 } \
347 ++sym; \
348 } \
349 printf(" in "); \
350 if (func && func->st_name) \
351 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
352 else \
353 printf("(NULL: fake?)"); \
354 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
355 } \
356 } }
357 SHOW_TEXTRELS(32)
358 SHOW_TEXTRELS(64)
359 }
360 if (!*found_textrels)
361 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
362
363 return NULL;
364}
365
366static void rpath_security_checks(elfobj *, char *);
367static void rpath_security_checks(elfobj *elf, char *item) {
368 struct stat st;
369 switch (*item) {
370 case '/': break;
371 case '.':
372 warnf("Security problem with relative RPATH '%s' in %s", item, elf->filename);
373 break;
374 case '\0':
375 warnf("Security problem NULL RPATH in %s", elf->filename);
376 break;
377 case '$':
378 if (fstat(elf->fd, &st) != -1)
379 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
380 warnf("Security problem with RPATH='%s' in %s with mode set of %o",
381 item, elf->filename, st.st_mode & 07777);
382 break;
383 default:
384 warnf("Maybe? sec problem with RPATH='%s' in %s", item, elf->filename);
385 break;
386 }
387}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 388static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{ 389{
161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 390 unsigned long i, s;
162 int i;
163 char *rpath, *runpath; 391 char *rpath, *runpath, **r;
164 void *strtbl_void; 392 void *strtbl_void;
165 393
166 if (!show_rpath) return; 394 if (!show_rpath) return;
167 395
168 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 396 strtbl_void = elf_findsecbyname(elf, ".dynstr");
169 rpath = runpath = NULL; 397 rpath = runpath = NULL;
170 398
171 if (strtbl_void) { 399 if (elf->phdr && strtbl_void) {
172#define SHOW_RPATH(B) \ 400#define SHOW_RPATH(B) \
173 if (elf->elf_class == ELFCLASS ## B) { \ 401 if (elf->elf_class == ELFCLASS ## B) { \
174 Elf ## B ## _Dyn *dyn; \ 402 Elf ## B ## _Dyn *dyn; \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 403 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 404 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 405 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
406 Elf ## B ## _Off offset; \
407 Elf ## B ## _Xword word; \
408 /* Scan all the program headers */ \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 409 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
410 /* Just scan dynamic headers */ \
179 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 411 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
412 offset = EGET(phdr[i].p_offset); \
413 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
414 /* Just scan dynamic RPATH/RUNPATH headers */ \
180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 415 dyn = DYN ## B (elf->data + offset); \
181 while (EGET(dyn->d_tag) != DT_NULL) { \ 416 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
182 if (EGET(dyn->d_tag) == DT_RPATH) { \ 417 if (word == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \ 418 r = &rpath; \
419 } else if (word == DT_RUNPATH) { \
420 r = &runpath; \
421 } else { \
422 ++dyn; \
423 continue; \
424 } \
425 /* Verify the memory is somewhat sane */ \
184 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 426 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
427 if (offset < (Elf ## B ## _Off)elf->len) { \
428 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
429 *r = (char*)(elf->data + offset); \
430 /* If quiet, don't output paths in ld.so.conf */ \
431 if (be_quiet) { \
432 size_t len; \
433 char *start, *end; \
434 /* note that we only 'chop' off leading known paths. */ \
435 /* since *r is read-only memory, we can only move the ptr forward. */ \
436 start = *r; \
437 /* scan each path in : delimited list */ \
438 while (start) { \
439 rpath_security_checks(elf, start); \
440 end = strchr(start, ':'); \
441 len = (end ? abs(end - start) : strlen(start)); \
442 for (s = 0; ldpaths[s]; ++s) { \
443 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
444 *r = (end ? end + 1 : NULL); \
445 break; \
446 } \
447 } \
448 if (!*r || !ldpaths[s] || !end) \
449 start = NULL; \
450 else \
451 start = start + len + 1; \
452 } \
453 } \
185 *found_rpath = 1; \ 454 if (*r) *found_rpath = 1; \
186 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
187 if (runpath) warn("ELF has multiple DT_RUNPATH's !?"); \
188 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
189 *found_rpath = 1; \
190 } \ 455 } \
191 ++dyn; \ 456 ++dyn; \
192 } \ 457 } \
193 } } 458 } }
194 SHOW_RPATH(32) 459 SHOW_RPATH(32)
195 SHOW_RPATH(64) 460 SHOW_RPATH(64)
196 } 461 }
462
463 if (be_wewy_wewy_quiet) return;
197 464
198 if (rpath && runpath) { 465 if (rpath && runpath) {
199 if (!strcmp(rpath, runpath)) { 466 if (!strcmp(rpath, runpath)) {
200 xstrcat(ret, runpath, ret_len); 467 xstrcat(ret, runpath, ret_len);
201 } else { 468 } else {
209 } else if (rpath || runpath) 476 } else if (rpath || runpath)
210 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 477 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
211 else if (!be_quiet) 478 else if (!be_quiet)
212 xstrcat(ret, " - ", ret_len); 479 xstrcat(ret, " - ", ret_len);
213} 480}
214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 481static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
215{ 482{
216 int i; 483 unsigned long i;
217 char *needed; 484 char *needed;
218 void *strtbl_void; 485 void *strtbl_void;
219 486
220 if (!show_needed) return; 487 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
221 488
222 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 489 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223 490
224 if (strtbl_void) { 491 if (elf->phdr && strtbl_void) {
225#define SHOW_NEEDED(B) \ 492#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \ 493 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \ 494 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 495 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 496 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 497 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
498 Elf ## B ## _Off offset; \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 499 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
232 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 500 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
501 offset = EGET(phdr[i].p_offset); \
502 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 503 dyn = DYN ## B (elf->data + offset); \
234 while (EGET(dyn->d_tag) != DT_NULL) { \ 504 while (EGET(dyn->d_tag) != DT_NULL) { \
235 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 505 if (EGET(dyn->d_tag) == DT_NEEDED) { \
236 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 506 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
507 if (offset >= (Elf ## B ## _Off)elf->len) { \
508 ++dyn; \
509 continue; \
510 } \
511 needed = (char*)(elf->data + offset); \
512 if (op == 0) { \
513 if (!be_wewy_wewy_quiet) { \
237 if (*found_needed) xchrcat(ret, ',', ret_len); \ 514 if (*found_needed) xchrcat(ret, ',', ret_len); \
238 xstrcat(ret, needed, ret_len); \ 515 xstrcat(ret, needed, ret_len); \
516 } \
239 *found_needed = 1; \ 517 *found_needed = 1; \
518 } else { \
519 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
520 *found_lib = 1; \
521 return (be_wewy_wewy_quiet ? NULL : needed); \
522 } \
523 } \
240 } \ 524 } \
241 ++dyn; \ 525 ++dyn; \
242 } \ 526 } \
243 } } 527 } }
244 SHOW_NEEDED(32) 528 SHOW_NEEDED(32)
245 SHOW_NEEDED(64) 529 SHOW_NEEDED(64)
530 if (op == 0 && !*found_needed && be_verbose)
531 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
246 } 532 }
533
534 return NULL;
247} 535}
248static char *scanelf_file_interp(elfobj *elf, char *found_interp) 536static char *scanelf_file_interp(elfobj *elf, char *found_interp)
249{ 537{
250 void *strtbl_void; 538 void *strtbl_void;
251 539
256 if (strtbl_void) { 544 if (strtbl_void) {
257#define SHOW_INTERP(B) \ 545#define SHOW_INTERP(B) \
258 if (elf->elf_class == ELFCLASS ## B) { \ 546 if (elf->elf_class == ELFCLASS ## B) { \
259 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 547 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
260 *found_interp = 1; \ 548 *found_interp = 1; \
261 return elf->data + EGET(strtbl->sh_offset); \ 549 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
262 } 550 }
263 SHOW_INTERP(32) 551 SHOW_INTERP(32)
264 SHOW_INTERP(64) 552 SHOW_INTERP(64)
265 } 553 }
266 return NULL; 554 return NULL;
267} 555}
556static char *scanelf_file_bind(elfobj *elf, char *found_bind)
557{
558 unsigned long i;
559 struct stat s;
560
561 if (!show_bind) return NULL;
562 if (!elf->phdr) return NULL;
563
564#define SHOW_BIND(B) \
565 if (elf->elf_class == ELFCLASS ## B) { \
566 Elf ## B ## _Dyn *dyn; \
567 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
568 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
569 Elf ## B ## _Off offset; \
570 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
571 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
572 offset = EGET(phdr[i].p_offset); \
573 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
574 dyn = DYN ## B (elf->data + offset); \
575 while (EGET(dyn->d_tag) != DT_NULL) { \
576 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
577 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
578 { \
579 if (be_quiet) return NULL; \
580 *found_bind = 1; \
581 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
582 } \
583 ++dyn; \
584 } \
585 } \
586 }
587 SHOW_BIND(32)
588 SHOW_BIND(64)
589
590 if (be_wewy_wewy_quiet) return NULL;
591
592 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
593 return NULL;
594 } else {
595 *found_bind = 1;
596 return (char *) "LAZY";
597 }
598}
599static char *scanelf_file_soname(elfobj *elf, char *found_soname)
600{
601 unsigned long i;
602 char *soname;
603 void *strtbl_void;
604
605 if (!show_soname) return NULL;
606
607 strtbl_void = elf_findsecbyname(elf, ".dynstr");
608
609 if (elf->phdr && strtbl_void) {
610#define SHOW_SONAME(B) \
611 if (elf->elf_class == ELFCLASS ## B) { \
612 Elf ## B ## _Dyn *dyn; \
613 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
614 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
615 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
616 Elf ## B ## _Off offset; \
617 /* only look for soname in shared objects */ \
618 if (ehdr->e_type != ET_DYN) \
619 return NULL; \
620 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
621 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
622 offset = EGET(phdr[i].p_offset); \
623 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
624 dyn = DYN ## B (elf->data + offset); \
625 while (EGET(dyn->d_tag) != DT_NULL) { \
626 if (EGET(dyn->d_tag) == DT_SONAME) { \
627 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
628 if (offset >= (Elf ## B ## _Off)elf->len) { \
629 ++dyn; \
630 continue; \
631 } \
632 soname = (char*)(elf->data + offset); \
633 *found_soname = 1; \
634 return (be_wewy_wewy_quiet ? NULL : soname); \
635 } \
636 ++dyn; \
637 } \
638 } }
639 SHOW_SONAME(32)
640 SHOW_SONAME(64)
641 }
642
643 return NULL;
644}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 645static char *scanelf_file_sym(elfobj *elf, char *found_sym)
269{ 646{
270 int i; 647 unsigned long i;
271 void *symtab_void, *strtab_void; 648 void *symtab_void, *strtab_void;
272 649
273 if (!find_sym) return NULL; 650 if (!find_sym) return NULL;
274 651
275 symtab_void = elf_findsecbyname(elf, ".symtab"); 652 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
276 strtab_void = elf_findsecbyname(elf, ".strtab");
277 653
278 if (symtab_void && strtab_void) { 654 if (symtab_void && strtab_void) {
279#define FIND_SYM(B) \ 655#define FIND_SYM(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \ 656 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 657 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 658 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
283 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 659 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
284 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 660 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
285 char *symname; \ 661 char *symname; \
286 for (i = 0; i < cnt; ++i) { \ 662 for (i = 0; i < cnt; ++i) { \
287 if (sym->st_name) { \ 663 if (sym->st_name) { \
288 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 664 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
289 if (*find_sym == '*') { \ 665 if (*find_sym == '*') { \
290 printf("%s(%s) %5lX %15s %s\n", \ 666 printf("%s(%s) %5lX %15s %s\n", \
291 ((*found_sym == 0) ? "\n\t" : "\t"), \ 667 ((*found_sym == 0) ? "\n\t" : "\t"), \
292 (char *)basename(filename), \ 668 elf->base_filename, \
293 (long)sym->st_size, \ 669 (long)sym->st_size, \
294 (char *)get_elfstttype(sym->st_info), \ 670 (char *)get_elfstttype(sym->st_info), \
295 symname); \ 671 symname); \
296 *found_sym = 1; \ 672 *found_sym = 1; \
297 } else if ((strcmp(find_sym, symname) == 0) || \ 673 } else if ((strcmp(find_sym, symname) == 0) || \
301 ++sym; \ 677 ++sym; \
302 } } 678 } }
303 FIND_SYM(32) 679 FIND_SYM(32)
304 FIND_SYM(64) 680 FIND_SYM(64)
305 } 681 }
682
683 if (be_wewy_wewy_quiet) return NULL;
684
306 if (*find_sym != '*' && *found_sym) 685 if (*find_sym != '*' && *found_sym)
307 return find_sym; 686 return find_sym;
308 if (be_quiet) 687 if (be_quiet)
309 return NULL; 688 return NULL;
310 else 689 else
311 return " - "; 690 return (char *)" - ";
312} 691}
313/* scan an elf file and show all the fun stuff */ 692/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout) 693#define prints(str) write(fileno(stdout), str, strlen(str))
315static void scanelf_file(const char *filename) 694static void scanelf_file(const char *filename)
316{ 695{
317 int i; 696 unsigned long i;
318 char found_pax, found_stack, found_relro, found_textrel, 697 char found_pax, found_phdr, found_relro, found_load, found_textrel,
319 found_rpath, found_needed, found_interp, found_sym, 698 found_rpath, found_needed, found_interp, found_bind, found_soname,
320 found_file; 699 found_sym, found_lib, found_file, found_textrels;
321 elfobj *elf; 700 elfobj *elf;
322 struct stat st; 701 struct stat st;
323 static char *out_buffer = NULL; 702 static char *out_buffer = NULL;
324 static size_t out_len; 703 static size_t out_len;
325 704
327 if (lstat(filename, &st) == -1) { 706 if (lstat(filename, &st) == -1) {
328 if (be_verbose > 2) printf("%s: does not exist\n", filename); 707 if (be_verbose > 2) printf("%s: does not exist\n", filename);
329 return; 708 return;
330 } 709 }
331 /* always handle regular files and handle symlinked files if no -y */ 710 /* always handle regular files and handle symlinked files if no -y */
332 if (!(S_ISREG(st.st_mode) || (S_ISLNK(st.st_mode) && scan_symlink))) { 711 if (S_ISLNK(st.st_mode)) {
712 if (!scan_symlink) return;
713 stat(filename, &st);
714 }
715 if (!S_ISREG(st.st_mode)) {
333 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 716 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
334 return; 717 return;
335 } 718 }
336 719
337 found_pax = found_stack = found_relro = found_textrel = \ 720 found_pax = found_phdr = found_relro = found_load = found_textrel = \
338 found_rpath = found_needed = found_interp = found_sym = \ 721 found_rpath = found_needed = found_interp = found_bind = found_soname = \
339 found_file = 0; 722 found_sym = found_lib = found_file = found_textrels = 0;
340 723
341 /* verify this is real ELF */ 724 /* verify this is real ELF */
342 if ((elf = readelf(filename)) == NULL) { 725 if ((elf = readelf(filename)) == NULL) {
343 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 726 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
344 return; 727 return;
345 } 728 }
346 729
347 if (be_verbose > 1) 730 if (be_verbose > 1)
348 printf("%s: scanning file {%s,%s}\n", filename, 731 printf("%s: scanning file {%s,%s}\n", filename,
349 get_elfeitype(elf, EI_CLASS, elf->elf_class), 732 get_elfeitype(EI_CLASS, elf->elf_class),
350 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA])); 733 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
351 else if (be_verbose) 734 else if (be_verbose)
352 printf("%s: scanning file\n", filename); 735 printf("%s: scanning file\n", filename);
353 736
354 /* init output buffer */ 737 /* init output buffer */
355 if (!out_buffer) { 738 if (!out_buffer) {
358 } 741 }
359 *out_buffer = '\0'; 742 *out_buffer = '\0';
360 743
361 /* show the header */ 744 /* show the header */
362 if (!be_quiet && show_banner) { 745 if (!be_quiet && show_banner) {
363 for (i=0; out_format[i]; ++i) { 746 for (i = 0; out_format[i]; ++i) {
364 if (out_format[i] != '%') continue; 747 if (!IS_MODIFIER(out_format[i])) continue;
365 748
366 switch (out_format[++i]) { 749 switch (out_format[++i]) {
367 case '%': break; 750 case '%': break;
751 case '#': break;
752 case 'F':
753 case 'p':
368 case 'F': prints("FILE "); break; 754 case 'f': prints("FILE "); found_file = 1; break;
369 case 'o': prints(" TYPE "); break; 755 case 'o': prints(" TYPE "); break;
370 case 'x': prints(" PAX "); break; 756 case 'x': prints(" PAX "); break;
371 case 'e': prints("STK/REL "); break; 757 case 'e': prints("STK/REL/PTL "); break;
372 case 't': prints("TEXTREL "); break; 758 case 't': prints("TEXTREL "); break;
373 case 'r': prints("RPATH "); break; 759 case 'r': prints("RPATH "); break;
374 case 'n': prints("NEEDED "); break; 760 case 'n': prints("NEEDED "); break;
375 case 'i': prints("INTERP "); break; 761 case 'i': prints("INTERP "); break;
762 case 'b': prints("BIND "); break;
763 case 'S': prints("SONAME "); break;
376 case 's': prints("SYM "); break; 764 case 's': prints("SYM "); break;
765 case 'N': prints("LIB "); break;
766 case 'T': prints("TEXTRELS "); break;
767 default: warnf("'%c' has no title ?", out_format[i]);
377 } 768 }
378 } 769 }
770 if (!found_file) prints("FILE ");
379 prints("\n"); 771 prints("\n");
772 found_file = 0;
380 show_banner = 0; 773 show_banner = 0;
381 } 774 }
382 775
383 /* dump all the good stuff */ 776 /* dump all the good stuff */
384 for (i=0; out_format[i]; ++i) { 777 for (i = 0; out_format[i]; ++i) {
385 const char *out; 778 const char *out;
779 const char *tmp;
386 780
387 /* make sure we trim leading spaces in quiet mode */ 781 /* make sure we trim leading spaces in quiet mode */
388 if (be_quiet && *out_buffer == ' ' && !out_buffer[1]) 782 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
389 *out_buffer = '\0'; 783 *out_buffer = '\0';
390 784
391 if (out_format[i] != '%') { 785 if (!IS_MODIFIER(out_format[i])) {
392 xchrcat(&out_buffer, out_format[i], &out_len); 786 xchrcat(&out_buffer, out_format[i], &out_len);
393 continue; 787 continue;
394 } 788 }
395 789
396 out = NULL; 790 out = NULL;
791 be_wewy_wewy_quiet = (out_format[i] == '#');
397 switch (out_format[++i]) { 792 switch (out_format[++i]) {
793 case '%':
794 case '#':
398 case '%': xchrcat(&out_buffer, '%', &out_len); break; 795 xchrcat(&out_buffer, out_format[i], &out_len); break;
399 case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break; 796 case 'F':
797 found_file = 1;
798 if (be_wewy_wewy_quiet) break;
799 xstrcat(&out_buffer, filename, &out_len);
800 break;
801 case 'p':
802 found_file = 1;
803 if (be_wewy_wewy_quiet) break;
804 tmp = filename;
805 if (search_path) {
806 ssize_t len_search = strlen(search_path);
807 ssize_t len_file = strlen(filename);
808 if (!strncmp(filename, search_path, len_search) && \
809 len_file > len_search)
810 tmp += len_search;
811 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
812 }
813 xstrcat(&out_buffer, tmp, &out_len);
814 break;
815 case 'f':
816 found_file = 1;
817 if (be_wewy_wewy_quiet) break;
818 tmp = strrchr(filename, '/');
819 tmp = (tmp == NULL ? filename : tmp+1);
820 xstrcat(&out_buffer, tmp, &out_len);
821 break;
400 case 'o': out = get_elfetype(elf); break; 822 case 'o': out = get_elfetype(elf); break;
401 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 823 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
402 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break; 824 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
403 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 825 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
826 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
404 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 827 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
828 case 'n':
405 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break; 829 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
406 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 830 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
831 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
832 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
407 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break; 833 case 's': out = scanelf_file_sym(elf, &found_sym); break;
834 default: warnf("'%c' has no scan code?", out_format[i]);
408 } 835 }
409 if (out) xstrcat(&out_buffer, out, &out_len); 836 if (out) xstrcat(&out_buffer, out, &out_len);
410 } 837 }
411 838
412 if (!found_file) { 839#define FOUND_SOMETHING() \
413 if (!be_quiet || found_pax || found_stack || found_textrel || \ 840 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
414 found_rpath || found_needed || found_interp || found_sym) 841 found_rpath || found_needed || found_interp || found_bind || \
842 found_soname || found_sym || found_lib || found_textrels)
843
844 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
845 xchrcat(&out_buffer, ' ', &out_len);
415 xstrcat(&out_buffer, filename, &out_len); 846 xstrcat(&out_buffer, filename, &out_len);
416 } 847 }
417 if (!(be_quiet && xemptybuffer(out_buffer))) 848 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
418 puts(out_buffer); 849 puts(out_buffer);
850 fflush(stdout);
851 }
419 852
420 unreadelf(elf); 853 unreadelf(elf);
421} 854}
422 855
423/* scan a directory for ET_EXEC files and print when we find one */ 856/* scan a directory for ET_EXEC files and print when we find one */
452 while ((dentry = readdir(dir))) { 885 while ((dentry = readdir(dir))) {
453 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 886 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
454 continue; 887 continue;
455 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 888 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
456 if (len >= sizeof(buf)) { 889 if (len >= sizeof(buf)) {
457 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 890 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
891 (unsigned long)len, (unsigned long)sizeof(buf));
458 continue; 892 continue;
459 } 893 }
460 sprintf(buf, "%s/%s", path, dentry->d_name); 894 sprintf(buf, "%s/%s", path, dentry->d_name);
461 if (lstat(buf, &st) != -1) { 895 if (lstat(buf, &st) != -1) {
462 if (S_ISREG(st.st_mode)) 896 if (S_ISREG(st.st_mode))
468 } 902 }
469 } 903 }
470 closedir(dir); 904 closedir(dir);
471} 905}
472 906
907static int scanelf_from_file(char *filename)
908{
909 FILE *fp = NULL;
910 char *p;
911 char path[_POSIX_PATH_MAX];
912
913 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
914 fp = stdin;
915 else if ((fp = fopen(filename, "r")) == NULL)
916 return 1;
917
918 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
919 if ((p = strchr(path, '\n')) != NULL)
920 *p = 0;
921 search_path = path;
922 scanelf_dir(path);
923 }
924 if (fp != stdin)
925 fclose(fp);
926 return 0;
927}
928
929static void load_ld_so_conf()
930{
931 FILE *fp = NULL;
932 char *p;
933 char path[_POSIX_PATH_MAX];
934 int i = 0;
935
936 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
937 return;
938
939 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
940 if (*path != '/')
941 continue;
942
943 if ((p = strrchr(path, '\r')) != NULL)
944 *p = 0;
945 if ((p = strchr(path, '\n')) != NULL)
946 *p = 0;
947
948 ldpaths[i++] = xstrdup(path);
949
950 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
951 break;
952 }
953 ldpaths[i] = NULL;
954
955 fclose(fp);
956}
957
473/* scan /etc/ld.so.conf for paths */ 958/* scan /etc/ld.so.conf for paths */
474static void scanelf_ldpath() 959static void scanelf_ldpath()
475{ 960{
476 char scan_l, scan_ul, scan_ull; 961 char scan_l, scan_ul, scan_ull;
477 char *path, *p; 962 int i = 0;
478 FILE *fp;
479 963
480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 964 if (!ldpaths[0])
481 err("Unable to open ld.so.conf: %s", strerror(errno)); 965 err("Unable to load any paths from ld.so.conf");
482 966
483 scan_l = scan_ul = scan_ull = 0; 967 scan_l = scan_ul = scan_ull = 0;
484 968
485 path = (char*)xmalloc(_POSIX_PATH_MAX); 969 while (ldpaths[i]) {
486 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
487 if (*path == '/') {
488 if ((p = strrchr(path, '\r')) != NULL)
489 *p = 0;
490 if ((p = strrchr(path, '\n')) != NULL)
491 *p = 0;
492 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1; 970 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
493 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 971 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
494 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 972 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
495 scanelf_dir(path); 973 scanelf_dir(ldpaths[i]);
974 ++i;
496 } 975 }
497 free(path);
498 fclose(fp);
499 976
500 if (!scan_l) scanelf_dir("/lib"); 977 if (!scan_l) scanelf_dir("/lib");
501 if (!scan_ul) scanelf_dir("/usr/lib"); 978 if (!scan_ul) scanelf_dir("/usr/lib");
502 if (!scan_ull) scanelf_dir("/usr/local/lib"); 979 if (!scan_ull) scanelf_dir("/usr/local/lib");
503} 980}
521} 998}
522 999
523 1000
524 1001
525/* usage / invocation handling functions */ 1002/* usage / invocation handling functions */
526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 1003#define PARSE_FLAGS "plRmyxetrnibSs:gN:TaqvF:f:o:BhV"
527#define a_argument required_argument 1004#define a_argument required_argument
528static struct option const long_opts[] = { 1005static struct option const long_opts[] = {
529 {"path", no_argument, NULL, 'p'}, 1006 {"path", no_argument, NULL, 'p'},
530 {"ldpath", no_argument, NULL, 'l'}, 1007 {"ldpath", no_argument, NULL, 'l'},
531 {"recursive", no_argument, NULL, 'R'}, 1008 {"recursive", no_argument, NULL, 'R'},
535 {"header", no_argument, NULL, 'e'}, 1012 {"header", no_argument, NULL, 'e'},
536 {"textrel", no_argument, NULL, 't'}, 1013 {"textrel", no_argument, NULL, 't'},
537 {"rpath", no_argument, NULL, 'r'}, 1014 {"rpath", no_argument, NULL, 'r'},
538 {"needed", no_argument, NULL, 'n'}, 1015 {"needed", no_argument, NULL, 'n'},
539 {"interp", no_argument, NULL, 'i'}, 1016 {"interp", no_argument, NULL, 'i'},
1017 {"bind", no_argument, NULL, 'b'},
1018 {"soname", no_argument, NULL, 'S'},
540 {"symbol", a_argument, NULL, 's'}, 1019 {"symbol", a_argument, NULL, 's'},
1020 {"lib", a_argument, NULL, 'N'},
1021 {"gmatch", no_argument, NULL, 'g'},
1022 {"textrels", no_argument, NULL, 'T'},
541 {"all", no_argument, NULL, 'a'}, 1023 {"all", no_argument, NULL, 'a'},
542 {"quiet", no_argument, NULL, 'q'}, 1024 {"quiet", no_argument, NULL, 'q'},
543 {"verbose", no_argument, NULL, 'v'}, 1025 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'}, 1026 {"format", a_argument, NULL, 'F'},
1027 {"from", a_argument, NULL, 'f'},
545 {"file", a_argument, NULL, 'o'}, 1028 {"file", a_argument, NULL, 'o'},
546 {"nobanner", no_argument, NULL, 'B'}, 1029 {"nobanner", no_argument, NULL, 'B'},
547 {"help", no_argument, NULL, 'h'}, 1030 {"help", no_argument, NULL, 'h'},
548 {"version", no_argument, NULL, 'V'}, 1031 {"version", no_argument, NULL, 'V'},
549 {NULL, no_argument, NULL, 0x0} 1032 {NULL, no_argument, NULL, 0x0}
550}; 1033};
1034
551static char *opts_help[] = { 1035static const char *opts_help[] = {
552 "Scan all directories in PATH environment", 1036 "Scan all directories in PATH environment",
553 "Scan all directories in /etc/ld.so.conf", 1037 "Scan all directories in /etc/ld.so.conf",
554 "Scan directories recursively", 1038 "Scan directories recursively",
555 "Don't recursively cross mount points", 1039 "Don't recursively cross mount points",
556 "Don't scan symlinks\n", 1040 "Don't scan symlinks\n",
557 "Print PaX markings", 1041 "Print PaX markings",
558 "Print GNU_STACK markings", 1042 "Print GNU_STACK/PT_LOAD markings",
559 "Print TEXTREL information", 1043 "Print TEXTREL information",
560 "Print RPATH information", 1044 "Print RPATH information",
561 "Print NEEDED information", 1045 "Print NEEDED information",
562 "Print INTERP information", 1046 "Print INTERP information",
1047 "Print BIND information",
1048 "Print SONAME information",
563 "Find a specified symbol", 1049 "Find a specified symbol",
1050 "Find a specified library",
1051 "Use strncmp to match libraries. (use with -N)",
1052 "Locate cause of TEXTREL",
564 "Print all scanned info (-x -e -t -r)\n", 1053 "Print all scanned info (-x -e -t -r -b)\n",
565 "Only output 'bad' things", 1054 "Only output 'bad' things",
566 "Be verbose (can be specified more than once)", 1055 "Be verbose (can be specified more than once)",
567 "Use specified format for output", 1056 "Use specified format for output",
1057 "Read input stream from a filename",
568 "Write output stream to a filename", 1058 "Write output stream to a filename",
569 "Don't display the header", 1059 "Don't display the header",
570 "Print this help and exit", 1060 "Print this help and exit",
571 "Print version and exit", 1061 "Print version and exit",
572 NULL 1062 NULL
573}; 1063};
574 1064
575/* display usage and exit */ 1065/* display usage and exit */
576static void usage(int status) 1066static void usage(int status)
577{ 1067{
578 int i; 1068 unsigned long i;
579 printf(" Scan ELF binaries for stuff\n\n" 1069 printf("* Scan ELF binaries for stuff\n\n"
580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1070 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
581 printf("Options: -[%s]\n", PARSE_FLAGS); 1071 printf("Options: -[%s]\n", PARSE_FLAGS);
582 for (i = 0; long_opts[i].name; ++i) 1072 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument) 1073 if (long_opts[i].has_arg == no_argument)
584 printf(" -%c, --%-13s %s\n", long_opts[i].val, 1074 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
585 long_opts[i].name, opts_help[i]); 1075 long_opts[i].name, opts_help[i]);
586 else 1076 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 1077 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
588 long_opts[i].name, opts_help[i]); 1078 long_opts[i].name, opts_help[i]);
1079
1080 if (status != EXIT_SUCCESS)
1081 exit(status);
1082
1083 puts("\nThe format modifiers for the -F option are:");
1084 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1085 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1086 puts(" i INTERP \tb BIND \ts symbol");
1087 puts(" N library \to Type \tT TEXTRELs");
1088 puts(" S SONAME");
1089 puts(" p filename (with search path removed)");
1090 puts(" f filename (short name/basename)");
1091 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1092
589 exit(status); 1093 exit(status);
590} 1094}
591 1095
592/* parse command line arguments and preform needed actions */ 1096/* parse command line arguments and preform needed actions */
593static void parseargs(int argc, char *argv[]) 1097static void parseargs(int argc, char *argv[])
594{ 1098{
595 int flag; 1099 int i;
1100 char *from_file = NULL;
596 1101
597 opterr = 0; 1102 opterr = 0;
598 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1103 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
599 switch (flag) { 1104 switch (i) {
600 1105
601 case 'V': 1106 case 'V':
602 printf("%s compiled %s\n%s\n" 1107 printf("pax-utils-%s: %s compiled %s\n%s\n"
603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1108 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
604 __FILE__, __DATE__, rcsid, argv0); 1109 VERSION, __FILE__, __DATE__, rcsid, argv0);
605 exit(EXIT_SUCCESS); 1110 exit(EXIT_SUCCESS);
606 break; 1111 break;
607 case 'h': usage(EXIT_SUCCESS); break; 1112 case 'h': usage(EXIT_SUCCESS); break;
608 1113 case 'f':
1114 if (from_file) err("Don't specify -f twice");
1115 from_file = xstrdup(optarg);
1116 break;
609 case 'o': { 1117 case 'o': {
610 FILE *fp = NULL; 1118 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout); 1119 if ((fp = freopen(optarg, "w", stdout)) == NULL)
612 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1120 err("Could not open output stream '%s': %s", optarg, strerror(errno));
614 stdout = fp; 1121 SET_STDOUT(fp);
615 break; 1122 break;
616 } 1123 }
617 1124
618 case 's': { 1125 case 's': {
619 size_t len; 1126 if (find_sym) warn("You prob don't want to specify -s twice");
620 find_sym = xstrdup(optarg); 1127 find_sym = optarg;
621 len = strlen(find_sym) + 1;
622 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1128 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
623 sprintf(versioned_symname, "%s@", find_sym); 1129 sprintf(versioned_symname, "%s@", find_sym);
624 break; 1130 break;
625 } 1131 }
626
627 case 'F': { 1132 case 'N': {
628 out_format = strdup(optarg); 1133 if (find_lib) warn("You prob don't want to specify -N twice");
1134 find_lib = optarg;
629 break; 1135 break;
630 } 1136 }
631 1137
1138 case 'F': {
1139 if (out_format) warn("You prob don't want to specify -F twice");
1140 out_format = optarg;
1141 break;
1142 }
1143
1144 case 'g': gmatch = 1;
632 case 'y': scan_symlink = 0; break; 1145 case 'y': scan_symlink = 0; break;
633 case 'B': show_banner = 0; break; 1146 case 'B': show_banner = 0; break;
634 case 'l': scan_ldpath = 1; break; 1147 case 'l': scan_ldpath = 1; break;
635 case 'p': scan_envpath = 1; break; 1148 case 'p': scan_envpath = 1; break;
636 case 'R': dir_recurse = 1; break; 1149 case 'R': dir_recurse = 1; break;
637 case 'm': dir_crossmount = 0; break; 1150 case 'm': dir_crossmount = 0; break;
638 case 'x': show_pax = 1; break; 1151 case 'x': show_pax = 1; break;
639 case 'e': show_stack = 1; break; 1152 case 'e': show_phdr = 1; break;
640 case 't': show_textrel = 1; break; 1153 case 't': show_textrel = 1; break;
641 case 'r': show_rpath = 1; break; 1154 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break; 1155 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break; 1156 case 'i': show_interp = 1; break;
1157 case 'b': show_bind = 1; break;
1158 case 'S': show_soname = 1; break;
1159 case 'T': show_textrels = 1; break;
644 case 'q': be_quiet = 1; break; 1160 case 'q': be_quiet = 1; break;
645 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1161 case 'v': be_verbose = (be_verbose % 20) + 1; break;
646 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break; 1162 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
647 1163
648 case ':': 1164 case ':':
649 warn("Option missing parameter\n"); 1165 err("Option missing parameter\n");
650 usage(EXIT_FAILURE);
651 break;
652 case '?': 1166 case '?':
653 warn("Unknown option\n"); 1167 err("Unknown option\n");
654 usage(EXIT_FAILURE);
655 break;
656 default: 1168 default:
657 err("Unhandled option '%c'", flag); 1169 err("Unhandled option '%c'", i);
658 break;
659 } 1170 }
660 } 1171 }
661
662 if (be_quiet && be_verbose)
663 err("You can be quiet or you can be verbose, not both, stupid");
664 1172
665 /* let the format option override all other options */ 1173 /* let the format option override all other options */
666 if (out_format) { 1174 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 1175 show_pax = show_phdr = show_textrel = show_rpath = \
1176 show_needed = show_interp = show_bind = show_soname = \
1177 show_textrels = 0;
668 for (flag=0; out_format[flag]; ++flag) { 1178 for (i = 0; out_format[i]; ++i) {
669 if (out_format[flag] != '%') continue; 1179 if (!IS_MODIFIER(out_format[i])) continue;
670 1180
671 switch (out_format[++flag]) { 1181 switch (out_format[++i]) {
672 case '%': break; 1182 case '%': break;
1183 case '#': break;
673 case 'F': break; 1184 case 'F': break;
1185 case 'p': break;
1186 case 'f': break;
674 case 's': break; 1187 case 's': break;
1188 case 'N': break;
675 case 'o': break; 1189 case 'o': break;
676 case 'x': show_pax = 1; break; 1190 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break; 1191 case 'e': show_phdr = 1; break;
678 case 't': show_textrel = 1; break; 1192 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break; 1193 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break; 1194 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 1; break; 1195 case 'i': show_interp = 1; break;
1196 case 'b': show_bind = 1; break;
1197 case 'S': show_soname = 1; break;
1198 case 'T': show_textrels = 1; break;
682 default: 1199 default:
683 err("Invalid format specifier '%c' (byte %i)", 1200 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1); 1201 out_format[i], i+1);
685 } 1202 }
686 } 1203 }
687 1204
688 /* construct our default format */ 1205 /* construct our default format */
689 } else { 1206 } else {
690 size_t fmt_len = 30; 1207 size_t fmt_len = 30;
691 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1208 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
692 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1209 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
693 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1210 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 1211 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1212 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1213 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1214 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1215 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1216 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1217 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1218 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1219 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1220 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1221 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 } 1222 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format); 1223 if (be_verbose > 2) printf("Format: %s\n", out_format);
703 1224
704 /* now lets actually do the scanning */ 1225 /* now lets actually do the scanning */
1226 if (scan_ldpath || (show_rpath && be_quiet))
1227 load_ld_so_conf();
705 if (scan_ldpath) scanelf_ldpath(); 1228 if (scan_ldpath) scanelf_ldpath();
706 if (scan_envpath) scanelf_envpath(); 1229 if (scan_envpath) scanelf_envpath();
1230 if (from_file) {
1231 scanelf_from_file(from_file);
1232 free(from_file);
1233 from_file = *argv;
1234 }
707 if (optind == argc && !scan_ldpath && !scan_envpath) 1235 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
708 err("Nothing to scan !?"); 1236 err("Nothing to scan !?");
709 while (optind < argc) 1237 while (optind < argc) {
710 scanelf_dir(argv[optind++]); 1238 search_path = argv[optind++];
1239 scanelf_dir(search_path);
1240 }
711 1241
712 /* clean up */ 1242 /* clean up */
713 if (find_sym) { 1243 if (versioned_symname) free(versioned_symname);
714 free(find_sym); 1244 for (i = 0; ldpaths[i]; ++i)
715 free(versioned_symname); 1245 free(ldpaths[i]);
716 }
717 if (out_format) free(out_format);
718} 1246}
719 1247
720 1248
721 1249
722/* utility funcs */ 1250/* utility funcs */
723static char *xstrdup(char *s) 1251static char *xstrdup(const char *s)
724{ 1252{
725 char *ret = strdup(s); 1253 char *ret = strdup(s);
726 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1254 if (!ret) err("Could not strdup(): %s", strerror(errno));
727 return ret; 1255 return ret;
728} 1256}
1257
729static void *xmalloc(size_t size) 1258static void *xmalloc(size_t size)
730{ 1259{
731 void *ret = malloc(size); 1260 void *ret = malloc(size);
732 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1261 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
733 return ret; 1262 return ret;
734} 1263}
1264
735static void xstrcat(char **dst, const char *src, size_t *curr_len) 1265static void xstrcat(char **dst, const char *src, size_t *curr_len)
736{ 1266{
737 long new_len; 1267 size_t new_len;
738 1268
739 new_len = strlen(*dst) + strlen(src); 1269 new_len = strlen(*dst) + strlen(src);
740 if (*curr_len <= new_len) { 1270 if (*curr_len <= new_len) {
741 *curr_len = new_len + (*curr_len / 2); 1271 *curr_len = new_len + (*curr_len / 2);
742 *dst = realloc(*dst, *curr_len); 1272 *dst = realloc(*dst, *curr_len);
744 err("could not realloc %li bytes", (unsigned long)*curr_len); 1274 err("could not realloc %li bytes", (unsigned long)*curr_len);
745 } 1275 }
746 1276
747 strcat(*dst, src); 1277 strcat(*dst, src);
748} 1278}
1279
749static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1280static inline void xchrcat(char **dst, const char append, size_t *curr_len)
750{ 1281{
751 static char my_app[2]; 1282 static char my_app[2];
752 my_app[0] = append; 1283 my_app[0] = append;
753 my_app[1] = '\0'; 1284 my_app[1] = '\0';
754 xstrcat(dst, my_app, curr_len); 1285 xstrcat(dst, my_app, curr_len);
755} 1286}
756static int xemptybuffer(const char *buff)
757{
758 long i;
759 for (i=0; buff[i]; ++i)
760 if (buff[i] != ' ')
761 return 0;
762 return 1;
763}
764 1287
765 1288
766 1289
767int main(int argc, char *argv[]) 1290int main(int argc, char *argv[])
768{ 1291{
769 if (argc < 2) 1292 if (argc < 2)
770 usage(EXIT_FAILURE); 1293 usage(EXIT_FAILURE);
771 parseargs(argc, argv); 1294 parseargs(argc, argv);
772 fclose(stdout); 1295 fclose(stdout);
1296#ifdef __BOUNDS_CHECKING_ON
1297 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
1298#endif
773 return EXIT_SUCCESS; 1299 return EXIT_SUCCESS;
774} 1300}

Legend:
Removed from v.1.43  
changed lines
  Added in v.1.93

  ViewVC Help
Powered by ViewVC 1.1.20