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

Legend:
Removed from v.1.32  
changed lines
  Added in v.1.71

  ViewVC Help
Powered by ViewVC 1.1.20