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

Legend:
Removed from v.1.32  
changed lines
  Added in v.1.64

  ViewVC Help
Powered by ViewVC 1.1.20