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

Legend:
Removed from v.1.35  
changed lines
  Added in v.1.52

  ViewVC Help
Powered by ViewVC 1.1.20