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

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

  ViewVC Help
Powered by ViewVC 1.1.20