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

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

  ViewVC Help
Powered by ViewVC 1.1.20