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

Legend:
Removed from v.1.67  
changed lines
  Added in v.1.91

  ViewVC Help
Powered by ViewVC 1.1.20