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

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

  ViewVC Help
Powered by ViewVC 1.1.20