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

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

  ViewVC Help
Powered by ViewVC 1.1.20