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

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

  ViewVC Help
Powered by ViewVC 1.1.20