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

Legend:
Removed from v.1.38  
changed lines
  Added in v.1.61

  ViewVC Help
Powered by ViewVC 1.1.20