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

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

  ViewVC Help
Powered by ViewVC 1.1.20