/[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.40 Revision 1.58
1/* 1/*
2 * Copyright 2003 Ned Ludd <solar@gentoo.org> 2 * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 * Copyright 1999-2005 Gentoo Foundation 3 * Copyright 1999-2005 Gentoo Foundation
4 * Distributed under the terms of the GNU General Public License v2 4 * Distributed under the terms of the GNU General Public License v2
5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.40 2005/04/21 00:13:03 solar Exp $ 5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.58 2005/05/24 22:04:34 vapier Exp $
6 * 6 *
7 ******************************************************************** 7 ********************************************************************
8 * This program is free software; you can redistribute it and/or 8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as 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 10 * published by the Free Software Foundation; either version 2 of the
33#include <getopt.h> 33#include <getopt.h>
34#include <assert.h> 34#include <assert.h>
35 35
36#include "paxelf.h" 36#include "paxelf.h"
37 37
38static const char *rcsid = "$Id: scanelf.c,v 1.40 2005/04/21 00:13:03 solar Exp $"; 38static const char *rcsid = "$Id: scanelf.c,v 1.58 2005/05/24 22:04:34 vapier Exp $";
39#define argv0 "scanelf" 39#define argv0 "scanelf"
40 40
41 41
42 42
43/* prototypes */ 43/* prototypes */
45static void scanelf_dir(const char *path); 45static void scanelf_dir(const char *path);
46static void scanelf_ldpath(); 46static void scanelf_ldpath();
47static void scanelf_envpath(); 47static void scanelf_envpath();
48static void usage(int status); 48static void usage(int status);
49static void parseargs(int argc, char *argv[]); 49static void parseargs(int argc, char *argv[]);
50static char *xstrdup(char *s);
51static void *xmalloc(size_t size);
52static void xstrcat(char **dst, const char *src, size_t *curr_len);
53static inline void xchrcat(char **dst, const char append, size_t *curr_len);
50 54
51/* variables to control behavior */ 55/* variables to control behavior */
56static char *ldpaths[256];
52static char scan_ldpath = 0; 57static char scan_ldpath = 0;
53static char scan_envpath = 0; 58static char scan_envpath = 0;
54static char scan_symlink = 1; 59static char scan_symlink = 1;
55static char dir_recurse = 0; 60static char dir_recurse = 0;
56static char dir_crossmount = 1; 61static char dir_crossmount = 1;
58static char show_stack = 0; 63static char show_stack = 0;
59static char show_textrel = 0; 64static char show_textrel = 0;
60static char show_rpath = 0; 65static char show_rpath = 0;
61static char show_needed = 0; 66static char show_needed = 0;
62static char show_interp = 0; 67static char show_interp = 0;
68static char show_bind = 0;
63static char show_banner = 1; 69static char show_banner = 1;
64static char be_quiet = 0; 70static char be_quiet = 0;
65static char be_verbose = 0; 71static char be_verbose = 0;
66static char *find_sym = NULL, *versioned_symname = NULL; 72static char *find_sym = NULL, *versioned_symname = NULL;
67static char *out_format = NULL; 73static char *out_format = NULL;
68 74
69 75
70 76
71/* sub-funcs for scanelf_file() */ 77/* sub-funcs for scanelf_file() */
72static void scanelf_file_pax(elfobj *elf, char *found_pax) 78static char *scanelf_file_pax(elfobj *elf, char *found_pax)
73{ 79{
74 char *paxflags; 80 static char *paxflags;
81
75 if (!show_pax) return; 82 if (!show_pax) return NULL;
76 83
77 paxflags = pax_short_hf_flags(PAX_FLAGS(elf)); 84 paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
78 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) { 85 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
79 *found_pax = 1; 86 *found_pax = 1;
80 printf("%s ", pax_short_hf_flags(PAX_FLAGS(elf))); 87 return paxflags;
81 } 88 }
89
90 return NULL;
82} 91}
83static void scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro) 92static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
84{ 93{
85 int i; 94 static char ret[8] = "--- ---";
95 char *found;
96 unsigned long i, off, shown;
97
86 if (!show_stack) return; 98 if (!show_stack) return NULL;
99
100 shown = 0;
101
102 if (elf->phdr) {
87#define SHOW_STACK(B) \ 103#define SHOW_STACK(B) \
88 if (elf->elf_class == ELFCLASS ## B) { \ 104 if (elf->elf_class == ELFCLASS ## B) { \
89 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 105 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
90 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 106 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
91 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 107 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
92 if (EGET(phdr[i].p_type) != PT_GNU_STACK && \ 108 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
109 found = found_stack; \
110 off = 0; \
93 EGET(phdr[i].p_type) != PT_GNU_RELRO) continue; \ 111 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
112 found = found_relro; \
113 off = 4; \
114 } else \
115 continue; \
94 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 116 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
95 continue; \ 117 continue; \
96 if (EGET(phdr[i].p_type) == PT_GNU_STACK) \
97 *found_stack = 1; \
98 if (EGET(phdr[i].p_type) == PT_GNU_RELRO) \
99 *found_relro = 1; \
100 printf("%s ", gnu_short_stack_flags(EGET(phdr[i].p_flags))); \ 118 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \
119 *found = 1; \
120 ++shown; \
101 } \ 121 } \
102 } 122 }
103 SHOW_STACK(32) 123 SHOW_STACK(32)
104 SHOW_STACK(64) 124 SHOW_STACK(64)
105 if (!be_quiet && !*found_stack) printf("--- "); 125 }
106 if (!be_quiet && !*found_relro) printf("--- "); 126
127 if (be_quiet && !shown)
128 return NULL;
129 else
130 return ret;
107} 131}
108static void scanelf_file_textrel(elfobj *elf, char *found_textrel) 132static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
109{ 133{
110 int i; 134 static char *ret = "TEXTREL";
135 unsigned long i;
136
111 if (!show_textrel) return; 137 if (!show_textrel) return NULL;
138
139 if (elf->phdr) {
112#define SHOW_TEXTREL(B) \ 140#define SHOW_TEXTREL(B) \
113 if (elf->elf_class == ELFCLASS ## B) { \ 141 if (elf->elf_class == ELFCLASS ## B) { \
114 Elf ## B ## _Dyn *dyn; \ 142 Elf ## B ## _Dyn *dyn; \
115 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 143 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
116 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 144 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
145 Elf ## B ## _Off offset; \
117 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 146 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
118 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 147 if (phdr[i].p_type != PT_DYNAMIC) continue; \
148 offset = EGET(phdr[i].p_offset); \
149 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
119 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 150 dyn = DYN ## B (elf->data + offset); \
120 while (EGET(dyn->d_tag) != DT_NULL) { \ 151 while (EGET(dyn->d_tag) != DT_NULL) { \
121 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 152 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
122 *found_textrel = 1; \ 153 *found_textrel = 1; \
123 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 154 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
124 printf("TEXTREL "); \ 155 return ret; \
125 } \ 156 } \
126 ++dyn; \ 157 ++dyn; \
127 } \ 158 } \
128 } } 159 } }
129 SHOW_TEXTREL(32) 160 SHOW_TEXTREL(32)
130 SHOW_TEXTREL(64) 161 SHOW_TEXTREL(64)
131 if (!be_quiet && !*found_textrel) printf("------- "); 162 }
163
164 if (be_quiet)
165 return NULL;
166 else
167 return " - ";
132} 168}
133static void scanelf_file_rpath(elfobj *elf, char *found_rpath) 169static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
134{ 170{
135 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 171 /* TODO: when checking RPATH entries, check each subpath (between :) in ld.so.conf */
136 int i; 172 unsigned long i, s;
137 char *rpath, *runpath; 173 char *rpath, *runpath, **r;
138 void *strtbl_void; 174 void *strtbl_void;
139 175
140 if (!show_rpath) return; 176 if (!show_rpath) return;
141 177
142 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 178 strtbl_void = elf_findsecbyname(elf, ".dynstr");
143 rpath = runpath = NULL; 179 rpath = runpath = NULL;
144 180
145 if (strtbl_void) { 181 if (elf->phdr && strtbl_void) {
146#define SHOW_RPATH(B) \ 182#define SHOW_RPATH(B) \
147 if (elf->elf_class == ELFCLASS ## B) { \ 183 if (elf->elf_class == ELFCLASS ## B) { \
148 Elf ## B ## _Dyn *dyn; \ 184 Elf ## B ## _Dyn *dyn; \
149 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 185 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
150 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 186 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
151 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 187 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
188 Elf ## B ## _Off offset; \
189 Elf ## B ## _Sxword word; \
190 /* Scan all the program headers */ \
152 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 191 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
192 /* Just scan dynamic headers */ \
153 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 193 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
194 offset = EGET(phdr[i].p_offset); \
195 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
196 /* Just scan dynamic RPATH/RUNPATH headers */ \
154 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 197 dyn = DYN ## B (elf->data + offset); \
155 while (EGET(dyn->d_tag) != DT_NULL) { \ 198 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
156 if (EGET(dyn->d_tag) == DT_RPATH) { \ 199 if (word == DT_RPATH) { \
200 r = &rpath; \
201 } else if (word == DT_RUNPATH) { \
202 r = &runpath; \
203 } else { \
204 ++dyn; \
205 continue; \
206 } \
207 /* Verify the memory is somewhat sane */ \
157 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 208 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
209 if (offset < elf->len) { \
210 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
211 *r = (char*)(elf->data + offset); \
212 /* If quiet, don't output paths in ld.so.conf */ \
213 if (be_quiet) \
214 for (s = 0; ldpaths[s]; ++s) \
215 if (!strcmp(ldpaths[s], *r)) { \
216 *r = NULL; \
217 break; \
218 } \
158 *found_rpath = 1; \ 219 if (*r) *found_rpath = 1; \
159 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
160 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
161 *found_rpath = 1; \
162 } \ 220 } \
163 ++dyn; \ 221 ++dyn; \
164 } \ 222 } \
165 } } 223 } }
166 SHOW_RPATH(32) 224 SHOW_RPATH(32)
167 SHOW_RPATH(64) 225 SHOW_RPATH(64)
168 } 226 }
227
169 if (rpath && runpath) { 228 if (rpath && runpath) {
170 if (!strcmp(rpath, runpath)) 229 if (!strcmp(rpath, runpath)) {
171 printf("%-5s ", runpath); 230 xstrcat(ret, runpath, ret_len);
172 else { 231 } else {
173 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath); 232 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
174 printf("{%s,%s} ", rpath, runpath); 233 xchrcat(ret, '{', ret_len);
234 xstrcat(ret, rpath, ret_len);
235 xchrcat(ret, ',', ret_len);
236 xstrcat(ret, runpath, ret_len);
237 xchrcat(ret, '}', ret_len);
175 } 238 }
176 } else if (rpath || runpath) 239 } else if (rpath || runpath)
177 printf("%-5s ", (runpath ? runpath : rpath)); 240 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
178 else if (!be_quiet && !*found_rpath) 241 else if (!be_quiet)
179 printf(" - "); 242 xstrcat(ret, " - ", ret_len);
180} 243}
181static void scanelf_file_needed(elfobj *elf, char *found_needed) 244static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len)
182{ 245{
183 int i; 246 unsigned long i;
184 char *needed; 247 char *needed;
185 void *strtbl_void; 248 void *strtbl_void;
186 249
187 if (!show_needed) return; 250 if (!show_needed) return;
188 251
189 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 252 strtbl_void = elf_findsecbyname(elf, ".dynstr");
190 253
191 if (strtbl_void) { 254 if (elf->phdr && strtbl_void) {
192#define SHOW_NEEDED(B) \ 255#define SHOW_NEEDED(B) \
193 if (elf->elf_class == ELFCLASS ## B) { \ 256 if (elf->elf_class == ELFCLASS ## B) { \
194 Elf ## B ## _Dyn *dyn; \ 257 Elf ## B ## _Dyn *dyn; \
195 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 258 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
196 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 259 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
197 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 260 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
261 Elf ## B ## _Off offset; \
198 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 262 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
199 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 263 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
264 offset = EGET(phdr[i].p_offset); \
265 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
200 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 266 dyn = DYN ## B (elf->data + offset); \
201 while (EGET(dyn->d_tag) != DT_NULL) { \ 267 while (EGET(dyn->d_tag) != DT_NULL) { \
202 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 268 if (EGET(dyn->d_tag) == DT_NEEDED) { \
203 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 269 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
204 if (*found_needed) printf(","); \ 270 if (offset >= elf->len) { \
205 printf("%s", needed); \ 271 ++dyn; \
272 continue; \
273 } \
274 needed = (char*)(elf->data + offset); \
275 if (*found_needed) xchrcat(ret, ',', ret_len); \
276 xstrcat(ret, needed, ret_len); \
206 *found_needed = 1; \ 277 *found_needed = 1; \
207 } \ 278 } \
208 ++dyn; \ 279 ++dyn; \
209 } \ 280 } \
210 } } 281 } }
211 SHOW_NEEDED(32) 282 SHOW_NEEDED(32)
212 SHOW_NEEDED(64) 283 SHOW_NEEDED(64)
213 } 284 }
214 if (!be_quiet && !*found_needed)
215 printf(" - ");
216 else if (*found_needed)
217 printf(" ");
218} 285}
219static void scanelf_file_interp(elfobj *elf, char *found_interp) 286static char *scanelf_file_interp(elfobj *elf, char *found_interp)
220{ 287{
221 void *strtbl_void; 288 void *strtbl_void;
222 289
223 if (!show_interp) return; 290 if (!show_interp) return NULL;
224 291
225 strtbl_void = elf_findsecbyname(elf, ".interp"); 292 strtbl_void = elf_findsecbyname(elf, ".interp");
226 293
227 if (strtbl_void) { 294 if (strtbl_void) {
228#define SHOW_INTERP(B) \ 295#define SHOW_INTERP(B) \
229 if (elf->elf_class == ELFCLASS ## B) { \ 296 if (elf->elf_class == ELFCLASS ## B) { \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 297 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
231 printf("%s ", elf->data + EGET(strtbl->sh_offset)); \
232 *found_interp = 1; \ 298 *found_interp = 1; \
299 return elf->data + EGET(strtbl->sh_offset); \
233 } 300 }
234 SHOW_INTERP(32) 301 SHOW_INTERP(32)
235 SHOW_INTERP(64) 302 SHOW_INTERP(64)
236 } 303 }
237 if (!be_quiet && !*found_interp) 304 return NULL;
238 printf(" - ");
239 else if (*found_interp)
240 printf(" ");
241} 305}
306static char *scanelf_file_bind(elfobj *elf, char *found_bind)
307{
308 unsigned long i;
309 struct stat s;
310
311 if (!show_bind) return NULL;
312 if (!elf->phdr) return NULL;
313
314#define SHOW_BIND(B) \
315 if (elf->elf_class == ELFCLASS ## B) { \
316 Elf ## B ## _Dyn *dyn; \
317 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
318 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
319 Elf ## B ## _Off offset; \
320 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
321 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
322 offset = EGET(phdr[i].p_offset); \
323 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
324 dyn = DYN ## B (elf->data + offset); \
325 while (EGET(dyn->d_tag) != DT_NULL) { \
326 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
327 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
328 { \
329 if (be_quiet) return NULL; \
330 *found_bind = 1; \
331 return "NOW"; \
332 } \
333 ++dyn; \
334 } \
335 } \
336 }
337 SHOW_BIND(32)
338 SHOW_BIND(64)
339
340 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
341 return NULL;
342 } else {
343 *found_bind = 1;
344 return "LAZY";
345 }
346}
242static void scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 347static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename)
243{ 348{
244 int i; 349 unsigned long i;
245 void *symtab_void, *strtab_void; 350 void *symtab_void, *strtab_void;
246 351
247 if (!find_sym) return; 352 if (!find_sym) return NULL;
248 353
249 symtab_void = elf_findsecbyname(elf, ".symtab"); 354 symtab_void = elf_findsecbyname(elf, ".symtab");
250 strtab_void = elf_findsecbyname(elf, ".strtab"); 355 strtab_void = elf_findsecbyname(elf, ".strtab");
251 356
252 if (symtab_void && strtab_void) { 357 if (symtab_void && strtab_void) {
253#define FIND_SYM(B) \ 358#define FIND_SYM(B) \
254 if (elf->elf_class == ELFCLASS ## B) { \ 359 if (elf->elf_class == ELFCLASS ## B) { \
255 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 360 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
256 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 361 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
257 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 362 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
258 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 363 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
259 char *symname; \ 364 char *symname; \
260 for (i = 0; i < cnt; ++i) { \ 365 for (i = 0; i < cnt; ++i) { \
261 if (sym->st_name) { \ 366 if (sym->st_name) { \
262 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 367 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
263 if (*find_sym == '*') { \ 368 if (*find_sym == '*') { \
275 ++sym; \ 380 ++sym; \
276 } } 381 } }
277 FIND_SYM(32) 382 FIND_SYM(32)
278 FIND_SYM(64) 383 FIND_SYM(64)
279 } 384 }
280 if (*find_sym != '*') { 385 if (*find_sym != '*' && *found_sym)
281 if (*found_sym) 386 return find_sym;
282 printf(" %s ", find_sym);
283 else if (!be_quiet) 387 if (be_quiet)
284 printf(" - "); 388 return NULL;
285 } 389 else
390 return " - ";
286} 391}
287/* scan an elf file and show all the fun stuff */ 392/* scan an elf file and show all the fun stuff */
393// #define prints(str) fputs(str, stdout)
394#define prints(str) write(fileno(stdout), str, strlen(str))
288static void scanelf_file(const char *filename) 395static void scanelf_file(const char *filename)
289{ 396{
290 int i; 397 unsigned long i;
291 char found_pax, found_stack, found_relro, found_textrel, 398 char found_pax, found_stack, found_relro, found_textrel,
292 found_rpath, found_needed, found_interp, found_sym, 399 found_rpath, found_needed, found_interp, found_bind,
293 found_file; 400 found_sym, found_file;
294 elfobj *elf; 401 elfobj *elf;
295 struct stat st; 402 struct stat st;
403 static char *out_buffer = NULL;
404 static size_t out_len;
296 405
297 /* make sure 'filename' exists */ 406 /* make sure 'filename' exists */
298 if (lstat(filename, &st) == -1) { 407 if (lstat(filename, &st) == -1) {
299 if (be_verbose > 2) printf("%s: does not exist\n", filename); 408 if (be_verbose > 2) printf("%s: does not exist\n", filename);
300 return; 409 return;
301 } 410 }
302 /* always handle regular files and handle symlinked files if no -y */ 411 /* always handle regular files and handle symlinked files if no -y */
303 if (!(S_ISREG(st.st_mode) || (S_ISLNK(st.st_mode) && scan_symlink))) { 412 if (S_ISLNK(st.st_mode)) {
413 if (!scan_symlink) return;
414 stat(filename, &st);
415 }
416 if (!S_ISREG(st.st_mode)) {
304 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 417 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
305 return; 418 return;
306 } 419 }
307 420
308 found_pax = found_stack = found_relro = found_textrel = \ 421 found_pax = found_stack = found_relro = found_textrel = \
309 found_rpath = found_needed = found_interp = found_sym = \ 422 found_rpath = found_needed = found_interp = found_bind = \
310 found_file = 0; 423 found_sym = found_file = 0;
311 424
312 /* verify this is real ELF */ 425 /* verify this is real ELF */
313 if ((elf = readelf(filename)) == NULL) { 426 if ((elf = readelf(filename)) == NULL) {
314 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 427 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
315 return; 428 return;
316 } 429 }
317 430
318 if (be_verbose > 1) 431 if (be_verbose > 1)
319 printf("%s: {%s,%s} scanning file\n", filename, 432 printf("%s: scanning file {%s,%s}\n", filename,
320 get_elfeitype(elf, EI_CLASS, elf->elf_class), 433 get_elfeitype(elf, EI_CLASS, elf->elf_class),
321 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA])); 434 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA]));
322 else if (be_verbose) 435 else if (be_verbose)
323 printf("%s: scanning file\n", filename); 436 printf("%s: scanning file\n", filename);
324 437
438 /* init output buffer */
439 if (!out_buffer) {
440 out_len = sizeof(char) * 80;
441 out_buffer = (char*)xmalloc(out_len);
442 }
443 *out_buffer = '\0';
444
325 /* show the header */ 445 /* show the header */
326 if (!be_quiet && show_banner) { 446 if (!be_quiet && show_banner) {
327 if (out_format) {
328 for (i=0; out_format[i]; ++i) { 447 for (i = 0; out_format[i]; ++i) {
329 if (out_format[i] != '%') continue; 448 if (out_format[i] != '%') continue;
330 449
331 switch (out_format[++i]) { 450 switch (out_format[++i]) {
332 case '%': break; 451 case '%': break;
452 case 'F': prints("FILE "); found_file = 1; break;
333 case 'F': printf("FILE "); break; 453 case 'o': prints(" TYPE "); break;
334 case 'x': printf(" PAX "); break; 454 case 'x': prints(" PAX "); break;
335 case 'e': printf("STK/REL "); break; 455 case 'e': prints("STK/REL "); break;
336 case 't': printf("TEXTREL "); break; 456 case 't': prints("TEXTREL "); break;
337 case 'r': printf("RPATH "); break; 457 case 'r': prints("RPATH "); break;
338 case 'n': printf("NEEDED "); break; 458 case 'n': prints("NEEDED "); break;
339 case 'i': printf("INTERP "); break; 459 case 'i': prints("INTERP "); break;
460 case 'b': prints("BIND "); break;
340 case 's': printf("SYM "); break; 461 case 's': prints("SYM "); break;
341 }
342 } 462 }
343 } else {
344 printf(" TYPE ");
345 if (show_pax) printf(" PAX ");
346 if (show_stack) printf("STK/REL ");
347 if (show_textrel) printf("TEXTREL ");
348 if (show_rpath) printf("RPATH ");
349 if (show_needed) printf("NEEDED ");
350 if (show_interp) printf("INTERP ");
351 if (find_sym) printf("SYM ");
352 } 463 }
353 if (!found_file) printf(" FILE"); 464 if (!found_file) prints("FILE ");
354 printf("\n"); 465 prints("\n");
466 found_file = 0;
355 show_banner = 0; 467 show_banner = 0;
356 } 468 }
357 469
358 /* dump all the good stuff */ 470 /* dump all the good stuff */
359 if (!be_quiet && !out_format)
360 printf("%-7s ", get_elfetype(elf));
361
362 if (out_format) {
363 for (i=0; out_format[i]; ++i) { 471 for (i = 0; out_format[i]; ++i) {
472 const char *out;
473
474 /* make sure we trim leading spaces in quiet mode */
475 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
476 *out_buffer = '\0';
477
364 if (out_format[i] != '%') { 478 if (out_format[i] != '%') {
365 printf("%c", out_format[i]); 479 xchrcat(&out_buffer, out_format[i], &out_len);
366 continue; 480 continue;
367 } 481 }
368 482
483 out = NULL;
369 switch (out_format[++i]) { 484 switch (out_format[++i]) {
370 case '%': printf("%%"); break; 485 case '%': xchrcat(&out_buffer, '%', &out_len); break;
371 case 'F': found_file = 1; printf("%s ", filename); break; 486 case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break;
487 case 'o': out = get_elfetype(elf); break;
372 case 'x': scanelf_file_pax(elf, &found_pax); break; 488 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
373 case 'e': scanelf_file_stack(elf, &found_stack, &found_relro); break; 489 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break;
374 case 't': scanelf_file_textrel(elf, &found_textrel); break; 490 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
375 case 'r': scanelf_file_rpath(elf, &found_rpath); break; 491 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
376 case 'n': scanelf_file_needed(elf, &found_needed); break; 492 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break;
377 case 'i': scanelf_file_interp(elf, &found_interp); break; 493 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
494 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
378 case 's': scanelf_file_sym(elf, &found_sym, filename); break; 495 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break;
379 } 496 }
497 if (out) xstrcat(&out_buffer, out, &out_len);
380 } 498 }
381 } else {
382 scanelf_file_pax(elf, &found_pax);
383 scanelf_file_stack(elf, &found_stack, &found_relro);
384 scanelf_file_textrel(elf, &found_textrel);
385 scanelf_file_rpath(elf, &found_rpath);
386 scanelf_file_needed(elf, &found_needed);
387 scanelf_file_interp(elf, &found_interp);
388 scanelf_file_sym(elf, &found_sym, filename);
389 }
390 499
391 if (!found_file) { 500#define FOUND_SOMETHING() \
392 if (!be_quiet || found_pax || found_stack || found_textrel || \ 501 (found_pax || found_stack || found_textrel || found_rpath || \
393 found_rpath || found_needed || found_sym) 502 found_needed || found_interp || found_bind || found_sym)
394 puts(filename); 503
395 } else { 504 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
396 printf("\n"); 505 xchrcat(&out_buffer, ' ', &out_len);
506 xstrcat(&out_buffer, filename, &out_len);
397 } 507 }
508 if (!be_quiet || (be_quiet && FOUND_SOMETHING()))
509 puts(out_buffer);
398 510
399 unreadelf(elf); 511 unreadelf(elf);
400} 512}
401 513
402/* scan a directory for ET_EXEC files and print when we find one */ 514/* scan a directory for ET_EXEC files and print when we find one */
447 } 559 }
448 } 560 }
449 closedir(dir); 561 closedir(dir);
450} 562}
451 563
564static int scanelf_from_file(char *filename)
565{
566 FILE *fp = NULL;
567 char *p;
568 char path[_POSIX_PATH_MAX];
569
570 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
571 fp = stdin;
572 else if ((fp = fopen(filename, "r")) == NULL)
573 return 1;
574
575 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
576 if ((p = strchr(path, '\n')) != NULL)
577 *p = 0;
578 scanelf_dir(path);
579 }
580 if (fp != stdin)
581 fclose(fp);
582 return 0;
583}
584
585static void load_ld_so_conf()
586{
587 FILE *fp = NULL;
588 char *p;
589 char path[_POSIX_PATH_MAX];
590 int i = 0;
591
592 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
593 return;
594
595 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
596 if (*path != '/')
597 continue;
598
599 if ((p = strrchr(path, '\r')) != NULL)
600 *p = 0;
601 if ((p = strchr(path, '\n')) != NULL)
602 *p = 0;
603
604 ldpaths[i++] = xstrdup(path);
605
606 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
607 break;
608 }
609 ldpaths[i] = NULL;
610
611 fclose(fp);
612}
613
452/* scan /etc/ld.so.conf for paths */ 614/* scan /etc/ld.so.conf for paths */
453static void scanelf_ldpath() 615static void scanelf_ldpath()
454{ 616{
455 char scan_l, scan_ul, scan_ull; 617 char scan_l, scan_ul, scan_ull;
456 char *path, *p; 618 int i = 0;
457 FILE *fp;
458 619
459 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 620 if (!ldpaths[0])
460 err("Unable to open ld.so.conf: %s", strerror(errno)); 621 err("Unable to load any paths from ld.so.conf");
461 622
462 scan_l = scan_ul = scan_ull = 0; 623 scan_l = scan_ul = scan_ull = 0;
463 624
464 if ((path = malloc(_POSIX_PATH_MAX)) == NULL) { 625 while (ldpaths[i]) {
465 warn("Can not malloc() memory for ldpath scanning");
466 return;
467 }
468 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
469 if (*path == '/') {
470 if ((p = strrchr(path, '\r')) != NULL)
471 *p = 0;
472 if ((p = strrchr(path, '\n')) != NULL)
473 *p = 0;
474 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1; 626 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
475 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 627 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
476 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 628 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
477 scanelf_dir(path); 629 scanelf_dir(ldpaths[i]);
630 ++i;
478 } 631 }
479 free(path);
480 fclose(fp);
481 632
482 if (!scan_l) scanelf_dir("/lib"); 633 if (!scan_l) scanelf_dir("/lib");
483 if (!scan_ul) scanelf_dir("/usr/lib"); 634 if (!scan_ul) scanelf_dir("/usr/lib");
484 if (!scan_ull) scanelf_dir("/usr/local/lib"); 635 if (!scan_ull) scanelf_dir("/usr/local/lib");
485} 636}
490 char *path, *p; 641 char *path, *p;
491 642
492 path = getenv("PATH"); 643 path = getenv("PATH");
493 if (!path) 644 if (!path)
494 err("PATH is not set in your env !"); 645 err("PATH is not set in your env !");
495 646 path = xstrdup(path);
496 if ((path = strdup(path)) == NULL)
497 err("strdup failed: %s", strerror(errno));
498 647
499 while ((p = strrchr(path, ':')) != NULL) { 648 while ((p = strrchr(path, ':')) != NULL) {
500 scanelf_dir(p + 1); 649 scanelf_dir(p + 1);
501 *p = 0; 650 *p = 0;
502 } 651 }
505} 654}
506 655
507 656
508 657
509/* usage / invocation handling functions */ 658/* usage / invocation handling functions */
510#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 659#define PARSE_FLAGS "plRmyxetrnibs:aqvF:f:o:BhV"
511#define a_argument required_argument 660#define a_argument required_argument
512static struct option const long_opts[] = { 661static struct option const long_opts[] = {
513 {"path", no_argument, NULL, 'p'}, 662 {"path", no_argument, NULL, 'p'},
514 {"ldpath", no_argument, NULL, 'l'}, 663 {"ldpath", no_argument, NULL, 'l'},
515 {"recursive", no_argument, NULL, 'R'}, 664 {"recursive", no_argument, NULL, 'R'},
519 {"header", no_argument, NULL, 'e'}, 668 {"header", no_argument, NULL, 'e'},
520 {"textrel", no_argument, NULL, 't'}, 669 {"textrel", no_argument, NULL, 't'},
521 {"rpath", no_argument, NULL, 'r'}, 670 {"rpath", no_argument, NULL, 'r'},
522 {"needed", no_argument, NULL, 'n'}, 671 {"needed", no_argument, NULL, 'n'},
523 {"interp", no_argument, NULL, 'i'}, 672 {"interp", no_argument, NULL, 'i'},
673 {"bind", no_argument, NULL, 'b'},
524 {"symbol", a_argument, NULL, 's'}, 674 {"symbol", a_argument, NULL, 's'},
525 {"all", no_argument, NULL, 'a'}, 675 {"all", no_argument, NULL, 'a'},
526 {"quiet", no_argument, NULL, 'q'}, 676 {"quiet", no_argument, NULL, 'q'},
527 {"verbose", no_argument, NULL, 'v'}, 677 {"verbose", no_argument, NULL, 'v'},
528 {"format", a_argument, NULL, 'F'}, 678 {"format", a_argument, NULL, 'F'},
679 {"from", a_argument, NULL, 'f'},
529 {"file", a_argument, NULL, 'o'}, 680 {"file", a_argument, NULL, 'o'},
530 {"nobanner", no_argument, NULL, 'B'}, 681 {"nobanner", no_argument, NULL, 'B'},
531 {"help", no_argument, NULL, 'h'}, 682 {"help", no_argument, NULL, 'h'},
532 {"version", no_argument, NULL, 'V'}, 683 {"version", no_argument, NULL, 'V'},
533 {NULL, no_argument, NULL, 0x0} 684 {NULL, no_argument, NULL, 0x0}
534}; 685};
686
535static char *opts_help[] = { 687static char *opts_help[] = {
536 "Scan all directories in PATH environment", 688 "Scan all directories in PATH environment",
537 "Scan all directories in /etc/ld.so.conf", 689 "Scan all directories in /etc/ld.so.conf",
538 "Scan directories recursively", 690 "Scan directories recursively",
539 "Don't recursively cross mount points", 691 "Don't recursively cross mount points",
542 "Print GNU_STACK markings", 694 "Print GNU_STACK markings",
543 "Print TEXTREL information", 695 "Print TEXTREL information",
544 "Print RPATH information", 696 "Print RPATH information",
545 "Print NEEDED information", 697 "Print NEEDED information",
546 "Print INTERP information", 698 "Print INTERP information",
699 "Print BIND information",
547 "Find a specified symbol", 700 "Find a specified symbol",
548 "Print all scanned info (-x -e -t -r)\n", 701 "Print all scanned info (-x -e -t -r -n -i -b)\n",
549 "Only output 'bad' things", 702 "Only output 'bad' things",
550 "Be verbose (can be specified more than once)", 703 "Be verbose (can be specified more than once)",
551 "Use specified format for output", 704 "Use specified format for output",
705 "Read input stream from a filename",
552 "Write output stream to a filename", 706 "Write output stream to a filename",
553 "Don't display the header", 707 "Don't display the header",
554 "Print this help and exit", 708 "Print this help and exit",
555 "Print version and exit", 709 "Print version and exit",
556 NULL 710 NULL
557}; 711};
558 712
559/* display usage and exit */ 713/* display usage and exit */
560static void usage(int status) 714static void usage(int status)
561{ 715{
562 int i; 716 unsigned long i;
563 printf(" Scan ELF binaries for stuff\n\n" 717 printf("* Scan ELF binaries for stuff\n\n"
564 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 718 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
565 printf("Options: -[%s]\n", PARSE_FLAGS); 719 printf("Options: -[%s]\n", PARSE_FLAGS);
566 for (i = 0; long_opts[i].name; ++i) 720 for (i = 0; long_opts[i].name; ++i)
567 if (long_opts[i].has_arg == no_argument) 721 if (long_opts[i].has_arg == no_argument)
568 printf(" -%c, --%-13s %s\n", long_opts[i].val, 722 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
569 long_opts[i].name, opts_help[i]); 723 long_opts[i].name, opts_help[i]);
570 else 724 else
571 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 725 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
572 long_opts[i].name, opts_help[i]); 726 long_opts[i].name, opts_help[i]);
727
728 if (status != EXIT_SUCCESS)
729 exit(status);
730
731 puts("\nThe format modifiers for the -F option are:");
732 puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO");
733 puts(" %t TEXTREL \t%r RPATH \t%n NEEDED");
734 puts(" %i INTERP \t%b BIND \t%s symbol");
735
573 exit(status); 736 exit(status);
574} 737}
575 738
576/* parse command line arguments and preform needed actions */ 739/* parse command line arguments and preform needed actions */
577static void parseargs(int argc, char *argv[]) 740static void parseargs(int argc, char *argv[])
578{ 741{
579 int flag; 742 int i;
743 char *from_file = NULL;
580 744
581 opterr = 0; 745 opterr = 0;
582 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 746 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
583 switch (flag) { 747 switch (i) {
584 748
585 case 'V': 749 case 'V':
586 printf("%s compiled %s\n%s\n" 750 printf("%s compiled %s\n%s\n"
587 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 751 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
588 __FILE__, __DATE__, rcsid, argv0); 752 __FILE__, __DATE__, rcsid, argv0);
589 exit(EXIT_SUCCESS); 753 exit(EXIT_SUCCESS);
590 break; 754 break;
591 case 'h': usage(EXIT_SUCCESS); break; 755 case 'h': usage(EXIT_SUCCESS); break;
592 756 case 'f':
757 if (from_file == NULL)
758 from_file = xstrdup(optarg);
759 break;
593 case 'o': { 760 case 'o': {
594 FILE *fp = NULL; 761 FILE *fp = NULL;
595 fp = freopen(optarg, "w", stdout); 762 fp = freopen(optarg, "w", stdout);
596 if (fp == NULL) 763 if (fp == NULL)
597 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 764 err("Could not open output stream '%s': %s", optarg, strerror(errno));
599 break; 766 break;
600 } 767 }
601 768
602 case 's': { 769 case 's': {
603 size_t len; 770 size_t len;
604 find_sym = strdup(optarg); 771 find_sym = xstrdup(optarg);
605 if (!find_sym) {
606 warnf("Could not malloc() mem for sym scan");
607 find_sym = NULL;
608 break;
609 }
610 len = strlen(find_sym) + 1; 772 len = strlen(find_sym) + 1;
611 versioned_symname = (char *)malloc(sizeof(char) * (len+1)); 773 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
612 if (!versioned_symname) {
613 free(find_sym);
614 find_sym = NULL;
615 warnf("Could not malloc() mem for sym scan");
616 break;
617 }
618 sprintf(versioned_symname, "%s@", find_sym); 774 sprintf(versioned_symname, "%s@", find_sym);
619 break; 775 break;
620 } 776 }
621 777
622 case 'F': { 778 case 'F': {
623 out_format = strdup(optarg); 779 out_format = xstrdup(optarg);
624 if (!out_format)
625 err("Could not malloc() mem for output format");
626 break; 780 break;
627 } 781 }
628 782
629 case 'y': scan_symlink = 0; break; 783 case 'y': scan_symlink = 0; break;
630 case 'B': show_banner = 0; break; 784 case 'B': show_banner = 0; break;
636 case 'e': show_stack = 1; break; 790 case 'e': show_stack = 1; break;
637 case 't': show_textrel = 1; break; 791 case 't': show_textrel = 1; break;
638 case 'r': show_rpath = 1; break; 792 case 'r': show_rpath = 1; break;
639 case 'n': show_needed = 1; break; 793 case 'n': show_needed = 1; break;
640 case 'i': show_interp = 1; break; 794 case 'i': show_interp = 1; break;
795 case 'b': show_bind = 1; break;
641 case 'q': be_quiet = 1; break; 796 case 'q': be_quiet = 1; break;
642 case 'v': be_verbose = (be_verbose % 20) + 1; break; 797 case 'v': be_verbose = (be_verbose % 20) + 1; break;
643 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break; 798 case 'a': show_pax = show_stack = show_textrel = show_rpath = \
799 show_needed = show_interp = show_bind = 1; break;
644 800
645 case ':': 801 case ':':
646 warn("Option missing parameter\n"); 802 err("Option missing parameter\n");
647 usage(EXIT_FAILURE);
648 break;
649 case '?': 803 case '?':
650 warn("Unknown option\n"); 804 err("Unknown option\n");
651 usage(EXIT_FAILURE);
652 break;
653 default: 805 default:
654 err("Unhandled option '%c'", flag); 806 err("Unhandled option '%c'", i);
655 break;
656 }
657 } 807 }
658 808 }
659 if (be_quiet && be_verbose)
660 err("You can be quiet or you can be verbose, not both, stupid");
661 809
662 /* let the format option override all other options */ 810 /* let the format option override all other options */
663 if (out_format) { 811 if (out_format) {
664 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 812 show_pax = show_stack = show_textrel = show_rpath = \
813 show_needed = show_interp = show_bind = 0;
665 for (flag=0; out_format[flag]; ++flag) { 814 for (i = 0; out_format[i]; ++i) {
666 if (out_format[flag] != '%') continue; 815 if (out_format[i] != '%') continue;
667 816
668 switch (out_format[++flag]) { 817 switch (out_format[++i]) {
669 case '%': break; 818 case '%': break;
670 case 'F': break; 819 case 'F': break;
671 case 's': break; 820 case 's': break;
821 case 'o': break;
672 case 'x': show_pax = 1; break; 822 case 'x': show_pax = 1; break;
673 case 'e': show_stack = 1; break; 823 case 'e': show_stack = 1; break;
674 case 't': show_textrel = 1; break; 824 case 't': show_textrel = 1; break;
675 case 'r': show_rpath = 1; break; 825 case 'r': show_rpath = 1; break;
676 case 'n': show_needed = 1; break; 826 case 'n': show_needed = 1; break;
677 case 'i': show_interp = 1; break; 827 case 'i': show_interp = 1; break;
828 case 'b': show_bind = 1; break;
678 default: 829 default:
679 err("Invalid format specifier '%c' (byte %i)", 830 err("Invalid format specifier '%c' (byte %i)",
680 out_format[flag], flag+1); 831 out_format[i], i+1);
681 } 832 }
682 } 833 }
834
835 /* construct our default format */
836 } else {
837 size_t fmt_len = 30;
838 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
839 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
840 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
841 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
842 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
843 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
844 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
845 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
846 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
847 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
848 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
683 } 849 }
850 if (be_verbose > 2) printf("Format: %s\n", out_format);
684 851
685 /* now lets actually do the scanning */ 852 /* now lets actually do the scanning */
853 if (scan_ldpath || (show_rpath && be_quiet))
854 load_ld_so_conf();
686 if (scan_ldpath) scanelf_ldpath(); 855 if (scan_ldpath) scanelf_ldpath();
687 if (scan_envpath) scanelf_envpath(); 856 if (scan_envpath) scanelf_envpath();
857 if (from_file) {
858 scanelf_from_file(from_file);
859 free(from_file);
860 from_file = *argv;
861 }
688 if (optind == argc && !scan_ldpath && !scan_envpath) 862 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
689 err("Nothing to scan !?"); 863 err("Nothing to scan !?");
690 while (optind < argc) 864 while (optind < argc)
691 scanelf_dir(argv[optind++]); 865 scanelf_dir(argv[optind++]);
692 866
693 /* clean up */ 867 /* clean up */
694 if (find_sym) { 868 if (find_sym) {
695 free(find_sym); 869 free(find_sym);
696 free(versioned_symname); 870 free(versioned_symname);
697 } 871 }
698 if (out_format) free(out_format); 872 if (out_format) free(out_format);
873 for (i = 0; ldpaths[i]; ++i)
874 free(ldpaths[i]);
699} 875}
700 876
877
878
879/* utility funcs */
880static char *xstrdup(char *s)
881{
882 char *ret = strdup(s);
883 if (!ret) err("Could not strdup(): %s", strerror(errno));
884 return ret;
885}
886
887static void *xmalloc(size_t size)
888{
889 void *ret = malloc(size);
890 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
891 return ret;
892}
893
894static void xstrcat(char **dst, const char *src, size_t *curr_len)
895{
896 long new_len;
897
898 new_len = strlen(*dst) + strlen(src);
899 if (*curr_len <= new_len) {
900 *curr_len = new_len + (*curr_len / 2);
901 *dst = realloc(*dst, *curr_len);
902 if (!*dst)
903 err("could not realloc %li bytes", (unsigned long)*curr_len);
904 }
905
906 strcat(*dst, src);
907}
908
909static inline void xchrcat(char **dst, const char append, size_t *curr_len)
910{
911 static char my_app[2];
912 my_app[0] = append;
913 my_app[1] = '\0';
914 xstrcat(dst, my_app, curr_len);
915}
701 916
702 917
703int main(int argc, char *argv[]) 918int main(int argc, char *argv[])
704{ 919{
705 if (argc < 2) 920 if (argc < 2)

Legend:
Removed from v.1.40  
changed lines
  Added in v.1.58

  ViewVC Help
Powered by ViewVC 1.1.20