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

Diff of /pax-utils/scanelf.c

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.20