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

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

  ViewVC Help
Powered by ViewVC 1.1.20