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

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

  ViewVC Help
Powered by ViewVC 1.1.20