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

Diff of /pax-utils/scanelf.c

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.20