/[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.43 Revision 1.90
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.43 2005/05/06 02:55:27 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.90 2005/12/04 18:12:44 vapier Exp $
6 * 5 *
7 ******************************************************************** 6 * Copyright 2003-2005 Ned Ludd - <solar@gentoo.org>
8 * This program is free software; you can redistribute it and/or 7 * Copyright 2004-2005 Mike Frysinger - <vapier@gentoo.org>
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21 * MA 02111-1307, USA.
22 */ 8 */
23 9
24#include <stdio.h> 10#include <stdio.h>
25#include <stdlib.h> 11#include <stdlib.h>
26#include <sys/types.h> 12#include <sys/types.h>
13#include <libgen.h>
14#include <limits.h>
27#define __USE_GNU 15#define __USE_GNU
28#include <string.h> 16#include <string.h>
29#include <errno.h> 17#include <errno.h>
30#include <unistd.h> 18#include <unistd.h>
31#include <sys/stat.h> 19#include <sys/stat.h>
32#include <dirent.h> 20#include <dirent.h>
33#include <getopt.h> 21#include <getopt.h>
34#include <assert.h> 22#include <assert.h>
35
36#include "paxelf.h" 23#include "paxinc.h"
37 24
38static const char *rcsid = "$Id: scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $"; 25static const char *rcsid = "$Id: scanelf.c,v 1.90 2005/12/04 18:12:44 vapier Exp $";
39#define argv0 "scanelf" 26#define argv0 "scanelf"
27
28#define IS_MODIFIER(c) (c == '%' || c == '#')
40 29
41 30
42 31
43/* prototypes */ 32/* prototypes */
44static void scanelf_file(const char *filename); 33static void scanelf_file(const char *filename);
45static void scanelf_dir(const char *path); 34static void scanelf_dir(const char *path);
46static void scanelf_ldpath(); 35static void scanelf_ldpath();
47static void scanelf_envpath(); 36static void scanelf_envpath();
48static void usage(int status); 37static void usage(int status);
49static void parseargs(int argc, char *argv[]); 38static void parseargs(int argc, char *argv[]);
50static char *xstrdup(char *s); 39static char *xstrdup(const char *s);
51static void *xmalloc(size_t size); 40static void *xmalloc(size_t size);
52static void xstrcat(char **dst, const char *src, size_t *curr_len); 41static void xstrcat(char **dst, const char *src, size_t *curr_len);
53static inline void xchrcat(char **dst, const char append, size_t *curr_len); 42static inline void xchrcat(char **dst, const char append, size_t *curr_len);
54static int xemptybuffer(const char *buff);
55 43
56/* variables to control behavior */ 44/* variables to control behavior */
45static char *ldpaths[256];
57static char scan_ldpath = 0; 46static char scan_ldpath = 0;
58static char scan_envpath = 0; 47static char scan_envpath = 0;
59static char scan_symlink = 1; 48static char scan_symlink = 1;
60static char dir_recurse = 0; 49static char dir_recurse = 0;
61static char dir_crossmount = 1; 50static char dir_crossmount = 1;
62static char show_pax = 0; 51static char show_pax = 0;
63static char show_stack = 0; 52static char show_phdr = 0;
64static char show_textrel = 0; 53static char show_textrel = 0;
65static char show_rpath = 0; 54static char show_rpath = 0;
66static char show_needed = 0; 55static char show_needed = 0;
67static char show_interp = 0; 56static char show_interp = 0;
57static char show_bind = 0;
58static char show_soname = 0;
59static char show_textrels = 0;
68static char show_banner = 1; 60static char show_banner = 1;
69static char be_quiet = 0; 61static char be_quiet = 0;
70static char be_verbose = 0; 62static char be_verbose = 0;
63static char be_wewy_wewy_quiet = 0;
71static char *find_sym = NULL, *versioned_symname = NULL; 64static char *find_sym = NULL, *versioned_symname = NULL;
65static char *find_lib = NULL;
72static char *out_format = NULL; 66static char *out_format = NULL;
73 67static char *search_path = NULL;
68static char gmatch = 0;
74 69
75 70
76/* sub-funcs for scanelf_file() */ 71/* sub-funcs for scanelf_file() */
72static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
73{
74 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
75#define GET_SYMTABS(B) \
76 if (elf->elf_class == ELFCLASS ## B) { \
77 Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
78 /* debug sections */ \
79 symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
80 strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
81 /* runtime sections */ \
82 dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
83 dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
84 if (symtab && dynsym) { \
85 *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
86 } else { \
87 *sym = (void*)(symtab ? symtab : dynsym); \
88 } \
89 if (strtab && dynstr) { \
90 *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
91 } else { \
92 *tab = (void*)(strtab ? strtab : dynstr); \
93 } \
94 }
95 GET_SYMTABS(32)
96 GET_SYMTABS(64)
97}
77static char *scanelf_file_pax(elfobj *elf, char *found_pax) 98static char *scanelf_file_pax(elfobj *elf, char *found_pax)
78{ 99{
79 static char *paxflags; 100 static char ret[7];
101 unsigned long i, shown;
80 102
81 if (!show_pax) return NULL; 103 if (!show_pax) return NULL;
82 104
83 paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
84 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
85 *found_pax = 1;
86 return paxflags;
87 }
88
89 return NULL;
90}
91static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
92{
93 static char ret[8];
94 char *found;
95 int i, off, shown;
96
97 if (!show_stack) return NULL;
98
99 shown = 0; 105 shown = 0;
100 strcpy(ret, "--- ---"); 106 memset(&ret, 0, sizeof(ret));
107
108 if (elf->phdr) {
101#define SHOW_STACK(B) \ 109#define SHOW_PAX(B) \
102 if (elf->elf_class == ELFCLASS ## B) { \ 110 if (elf->elf_class == ELFCLASS ## B) { \
103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 111 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 112 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 113 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
114 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
115 continue; \
116 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
117 continue; \
118 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
119 *found_pax = 1; \
120 ++shown; \
121 break; \
122 } \
123 }
124 SHOW_PAX(32)
125 SHOW_PAX(64)
126 }
127
128 /* fall back to EI_PAX if no PT_PAX was found */
129 if (!*ret) {
130 static char *paxflags;
131 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
132 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
133 *found_pax = 1;
134 return (be_wewy_wewy_quiet ? NULL : paxflags);
135 }
136 strncpy(ret, paxflags, sizeof(ret));
137 }
138
139 if (be_wewy_wewy_quiet || (be_quiet && !shown))
140 return NULL;
141 else
142 return ret;
143}
144
145static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
146{
147 static char ret[12];
148 char *found;
149 unsigned long i, off, shown, check_flags;
150 unsigned char multi_stack, multi_relro, multi_load;
151
152 if (!show_phdr) return NULL;
153
154 memcpy(ret, "--- --- ---\0", 12);
155
156 shown = 0;
157 multi_stack = multi_relro = multi_load = 0;
158
159 if (elf->phdr) {
160#define SHOW_PHDR(B) \
161 if (elf->elf_class == ELFCLASS ## B) { \
162 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
163 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
164 uint32_t flags; \
165 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
106 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 166 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
167 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
107 found = found_stack; \ 168 found = found_phdr; \
108 off = 0; \ 169 off = 0; \
170 check_flags = PF_X; \
109 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 171 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
172 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
110 found = found_relro; \ 173 found = found_relro; \
111 off = 3; \ 174 off = 4; \
175 check_flags = PF_X; \
176 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
177 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \
178 found = found_load; \
179 off = 8; \
180 check_flags = PF_W|PF_X; \
112 } else \ 181 } else \
113 continue; \ 182 continue; \
114 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 183 flags = EGET(phdr[i].p_flags); \
184 if (be_quiet && ((flags & check_flags) != check_flags)) \
115 continue; \ 185 continue; \
116 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \ 186 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \
117 *found = 1; \ 187 *found = 1; \
118 ++shown; \ 188 ++shown; \
119 } \ 189 } \
120 } 190 }
121 SHOW_STACK(32) 191 SHOW_PHDR(32)
122 SHOW_STACK(64) 192 SHOW_PHDR(64)
123 if (be_quiet && !shown) 193 }
194
195 if (be_wewy_wewy_quiet || (be_quiet && !shown))
124 return NULL; 196 return NULL;
125 else 197 else
126 return ret; 198 return ret;
127} 199}
128static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 200static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
129{ 201{
130 static char *ret = "TEXTREL"; 202 static const char *ret = "TEXTREL";
131 int i; 203 unsigned long i;
132 204
133 if (!show_textrel) return NULL; 205 if (!show_textrel && !show_textrels) return NULL;
134 206
207 if (elf->phdr) {
135#define SHOW_TEXTREL(B) \ 208#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 209 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \ 210 Elf ## B ## _Dyn *dyn; \
138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 211 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 212 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
213 Elf ## B ## _Off offset; \
140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 214 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
141 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 215 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
216 offset = EGET(phdr[i].p_offset); \
217 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 218 dyn = DYN ## B (elf->data + offset); \
143 while (EGET(dyn->d_tag) != DT_NULL) { \ 219 while (EGET(dyn->d_tag) != DT_NULL) { \
144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 220 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
145 *found_textrel = 1; \ 221 *found_textrel = 1; \
146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 222 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \ 223 return (be_wewy_wewy_quiet ? NULL : ret); \
148 } \ 224 } \
149 ++dyn; \ 225 ++dyn; \
150 } \ 226 } \
151 } } 227 } }
152 SHOW_TEXTREL(32) 228 SHOW_TEXTREL(32)
153 SHOW_TEXTREL(64) 229 SHOW_TEXTREL(64)
154 if (be_quiet) 230 }
231
232 if (be_quiet || be_wewy_wewy_quiet)
155 return NULL; 233 return NULL;
156 else 234 else
157 return " - "; 235 return " - ";
158} 236}
237static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
238{
239 unsigned long s, r, rmax;
240 void *symtab_void, *strtab_void, *text_void;
241
242 if (!show_textrels) return NULL;
243
244 /* don't search for TEXTREL's if the ELF doesn't have any */
245 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
246 if (!*found_textrel) return NULL;
247
248 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
249 text_void = elf_findsecbyname(elf, ".text");
250
251 if (symtab_void && strtab_void && text_void && elf->shdr) {
252#define SHOW_TEXTRELS(B) \
253 if (elf->elf_class == ELFCLASS ## B) { \
254 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
255 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
256 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
257 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
258 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
259 Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
260 uint ## B ## _t memsz = EGET(text->sh_size); \
261 Elf ## B ## _Rel *rel; \
262 Elf ## B ## _Rela *rela; \
263 /* search the section headers for relocations */ \
264 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
265 uint32_t sh_type = EGET(shdr[s].sh_type); \
266 if (sh_type == SHT_REL) { \
267 rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
268 rela = NULL; \
269 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
270 } else if (sh_type == SHT_RELA) { \
271 rel = NULL; \
272 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
273 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
274 } else \
275 continue; \
276 /* now see if any of the relocs are in the .text */ \
277 for (r = 0; r < rmax; ++r) { \
278 unsigned long sym_max; \
279 Elf ## B ## _Addr offset_tmp; \
280 Elf ## B ## _Sym *func; \
281 Elf ## B ## _Sym *sym; \
282 Elf ## B ## _Addr r_offset; \
283 uint ## B ## _t r_info; \
284 if (sh_type == SHT_REL) { \
285 r_offset = EGET(rel[r].r_offset); \
286 r_info = EGET(rel[r].r_info); \
287 } else { \
288 r_offset = EGET(rela[r].r_offset); \
289 r_info = EGET(rela[r].r_info); \
290 } \
291 /* make sure this relocation is inside of the .text */ \
292 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
293 if (be_verbose <= 2) continue; \
294 } else \
295 *found_textrels = 1; \
296 /* locate this relocation symbol name */ \
297 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
298 sym_max = ELF ## B ## _R_SYM(r_info); \
299 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
300 sym += sym_max; \
301 else \
302 sym = NULL; \
303 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
304 /* show the raw details about this reloc */ \
305 printf(" %s: ", elf->base_filename); \
306 if (sym && sym->st_name) \
307 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
308 else \
309 printf("(memory/fake?)"); \
310 printf(" [0x%lX]", (unsigned long)r_offset); \
311 /* now try to find the closest symbol that this rel is probably in */ \
312 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
313 func = NULL; \
314 offset_tmp = 0; \
315 while (sym_max--) { \
316 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
317 func = sym; \
318 offset_tmp = EGET(sym->st_value); \
319 } \
320 ++sym; \
321 } \
322 printf(" in "); \
323 if (func && func->st_name) \
324 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
325 else \
326 printf("(NULL: fake?)"); \
327 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
328 } \
329 } }
330 SHOW_TEXTRELS(32)
331 SHOW_TEXTRELS(64)
332 }
333 if (!*found_textrels)
334 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
335
336 return NULL;
337}
338
339static void rpath_security_checks(elfobj *, char *);
340static void rpath_security_checks(elfobj *elf, char *item) {
341 struct stat st;
342 switch (*item) {
343 case '/': break;
344 case '.':
345 warnf("Security problem with relative RPATH '%s' in %s", item, elf->filename);
346 break;
347 case '\0':
348 warnf("Security problem NULL RPATH in %s", elf->filename);
349 break;
350 case '$':
351 if (fstat(elf->fd, &st) != -1)
352 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
353 warnf("Security problem with RPATH='%s' in %s with mode set of %o",
354 item, elf->filename, st.st_mode & 07777);
355 break;
356 default:
357 warnf("Maybe? sec problem with RPATH='%s' in %s", item, elf->filename);
358 break;
359 }
360}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 361static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{ 362{
161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 363 unsigned long i, s;
162 int i;
163 char *rpath, *runpath; 364 char *rpath, *runpath, **r;
164 void *strtbl_void; 365 void *strtbl_void;
165 366
166 if (!show_rpath) return; 367 if (!show_rpath) return;
167 368
168 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 369 strtbl_void = elf_findsecbyname(elf, ".dynstr");
169 rpath = runpath = NULL; 370 rpath = runpath = NULL;
170 371
171 if (strtbl_void) { 372 if (elf->phdr && strtbl_void) {
172#define SHOW_RPATH(B) \ 373#define SHOW_RPATH(B) \
173 if (elf->elf_class == ELFCLASS ## B) { \ 374 if (elf->elf_class == ELFCLASS ## B) { \
174 Elf ## B ## _Dyn *dyn; \ 375 Elf ## B ## _Dyn *dyn; \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 376 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 377 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 378 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
379 Elf ## B ## _Off offset; \
380 Elf ## B ## _Xword word; \
381 /* Scan all the program headers */ \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 382 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
383 /* Just scan dynamic headers */ \
179 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 384 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
385 offset = EGET(phdr[i].p_offset); \
386 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
387 /* Just scan dynamic RPATH/RUNPATH headers */ \
180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 388 dyn = DYN ## B (elf->data + offset); \
181 while (EGET(dyn->d_tag) != DT_NULL) { \ 389 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
182 if (EGET(dyn->d_tag) == DT_RPATH) { \ 390 if (word == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \ 391 r = &rpath; \
392 } else if (word == DT_RUNPATH) { \
393 r = &runpath; \
394 } else { \
395 ++dyn; \
396 continue; \
397 } \
398 /* Verify the memory is somewhat sane */ \
184 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 399 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
400 if (offset < (Elf ## B ## _Off)elf->len) { \
401 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
402 *r = (char*)(elf->data + offset); \
403 /* If quiet, don't output paths in ld.so.conf */ \
404 if (be_quiet) { \
405 size_t len; \
406 char *start, *end; \
407 /* note that we only 'chop' off leading known paths. */ \
408 /* since *r is read-only memory, we can only move the ptr forward. */ \
409 start = *r; \
410 /* scan each path in : delimited list */ \
411 while (start) { \
412 rpath_security_checks(elf, start); \
413 end = strchr(start, ':'); \
414 len = (end ? abs(end - start) : strlen(start)); \
415 for (s = 0; ldpaths[s]; ++s) { \
416 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
417 *r = (end ? end + 1 : NULL); \
418 break; \
419 } \
420 } \
421 if (!*r || !ldpaths[s] || !end) \
422 start = NULL; \
423 else \
424 start = start + len + 1; \
425 } \
426 } \
185 *found_rpath = 1; \ 427 if (*r) *found_rpath = 1; \
186 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
187 if (runpath) warn("ELF has multiple DT_RUNPATH's !?"); \
188 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
189 *found_rpath = 1; \
190 } \ 428 } \
191 ++dyn; \ 429 ++dyn; \
192 } \ 430 } \
193 } } 431 } }
194 SHOW_RPATH(32) 432 SHOW_RPATH(32)
195 SHOW_RPATH(64) 433 SHOW_RPATH(64)
196 } 434 }
435
436 if (be_wewy_wewy_quiet) return;
197 437
198 if (rpath && runpath) { 438 if (rpath && runpath) {
199 if (!strcmp(rpath, runpath)) { 439 if (!strcmp(rpath, runpath)) {
200 xstrcat(ret, runpath, ret_len); 440 xstrcat(ret, runpath, ret_len);
201 } else { 441 } else {
209 } else if (rpath || runpath) 449 } else if (rpath || runpath)
210 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 450 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
211 else if (!be_quiet) 451 else if (!be_quiet)
212 xstrcat(ret, " - ", ret_len); 452 xstrcat(ret, " - ", ret_len);
213} 453}
214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 454static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
215{ 455{
216 int i; 456 unsigned long i;
217 char *needed; 457 char *needed;
218 void *strtbl_void; 458 void *strtbl_void;
219 459
220 if (!show_needed) return; 460 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
221 461
222 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 462 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223 463
224 if (strtbl_void) { 464 if (elf->phdr && strtbl_void) {
225#define SHOW_NEEDED(B) \ 465#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \ 466 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \ 467 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 468 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 469 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 470 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
471 Elf ## B ## _Off offset; \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 472 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
232 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 473 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
474 offset = EGET(phdr[i].p_offset); \
475 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 476 dyn = DYN ## B (elf->data + offset); \
234 while (EGET(dyn->d_tag) != DT_NULL) { \ 477 while (EGET(dyn->d_tag) != DT_NULL) { \
235 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 478 if (EGET(dyn->d_tag) == DT_NEEDED) { \
236 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 479 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
480 if (offset >= (Elf ## B ## _Off)elf->len) { \
481 ++dyn; \
482 continue; \
483 } \
484 needed = (char*)(elf->data + offset); \
485 if (op == 0) { \
486 if (!be_wewy_wewy_quiet) { \
237 if (*found_needed) xchrcat(ret, ',', ret_len); \ 487 if (*found_needed) xchrcat(ret, ',', ret_len); \
238 xstrcat(ret, needed, ret_len); \ 488 xstrcat(ret, needed, ret_len); \
489 } \
239 *found_needed = 1; \ 490 *found_needed = 1; \
491 } else { \
492 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
493 *found_lib = 1; \
494 return (be_wewy_wewy_quiet ? NULL : needed); \
495 } \
496 } \
240 } \ 497 } \
241 ++dyn; \ 498 ++dyn; \
242 } \ 499 } \
243 } } 500 } }
244 SHOW_NEEDED(32) 501 SHOW_NEEDED(32)
245 SHOW_NEEDED(64) 502 SHOW_NEEDED(64)
503 if (op == 0 && !*found_needed && be_verbose)
504 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
246 } 505 }
506
507 return NULL;
247} 508}
248static char *scanelf_file_interp(elfobj *elf, char *found_interp) 509static char *scanelf_file_interp(elfobj *elf, char *found_interp)
249{ 510{
250 void *strtbl_void; 511 void *strtbl_void;
251 512
256 if (strtbl_void) { 517 if (strtbl_void) {
257#define SHOW_INTERP(B) \ 518#define SHOW_INTERP(B) \
258 if (elf->elf_class == ELFCLASS ## B) { \ 519 if (elf->elf_class == ELFCLASS ## B) { \
259 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 520 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
260 *found_interp = 1; \ 521 *found_interp = 1; \
261 return elf->data + EGET(strtbl->sh_offset); \ 522 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
262 } 523 }
263 SHOW_INTERP(32) 524 SHOW_INTERP(32)
264 SHOW_INTERP(64) 525 SHOW_INTERP(64)
265 } 526 }
266 return NULL; 527 return NULL;
267} 528}
529static char *scanelf_file_bind(elfobj *elf, char *found_bind)
530{
531 unsigned long i;
532 struct stat s;
533
534 if (!show_bind) return NULL;
535 if (!elf->phdr) return NULL;
536
537#define SHOW_BIND(B) \
538 if (elf->elf_class == ELFCLASS ## B) { \
539 Elf ## B ## _Dyn *dyn; \
540 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
541 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
542 Elf ## B ## _Off offset; \
543 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
544 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
545 offset = EGET(phdr[i].p_offset); \
546 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
547 dyn = DYN ## B (elf->data + offset); \
548 while (EGET(dyn->d_tag) != DT_NULL) { \
549 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
550 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
551 { \
552 if (be_quiet) return NULL; \
553 *found_bind = 1; \
554 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
555 } \
556 ++dyn; \
557 } \
558 } \
559 }
560 SHOW_BIND(32)
561 SHOW_BIND(64)
562
563 if (be_wewy_wewy_quiet) return NULL;
564
565 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
566 return NULL;
567 } else {
568 *found_bind = 1;
569 return (char *) "LAZY";
570 }
571}
572static char *scanelf_file_soname(elfobj *elf, char *found_soname)
573{
574 unsigned long i;
575 char *soname;
576 void *strtbl_void;
577
578 if (!show_soname) return NULL;
579
580 strtbl_void = elf_findsecbyname(elf, ".dynstr");
581
582 if (elf->phdr && strtbl_void) {
583#define SHOW_SONAME(B) \
584 if (elf->elf_class == ELFCLASS ## B) { \
585 Elf ## B ## _Dyn *dyn; \
586 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
587 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
588 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
589 Elf ## B ## _Off offset; \
590 /* only look for soname in shared objects */ \
591 if (ehdr->e_type != ET_DYN) \
592 return NULL; \
593 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
594 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
595 offset = EGET(phdr[i].p_offset); \
596 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
597 dyn = DYN ## B (elf->data + offset); \
598 while (EGET(dyn->d_tag) != DT_NULL) { \
599 if (EGET(dyn->d_tag) == DT_SONAME) { \
600 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
601 if (offset >= (Elf ## B ## _Off)elf->len) { \
602 ++dyn; \
603 continue; \
604 } \
605 soname = (char*)(elf->data + offset); \
606 *found_soname = 1; \
607 return (be_wewy_wewy_quiet ? NULL : soname); \
608 } \
609 ++dyn; \
610 } \
611 } }
612 SHOW_SONAME(32)
613 SHOW_SONAME(64)
614 }
615
616 return NULL;
617}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 618static char *scanelf_file_sym(elfobj *elf, char *found_sym)
269{ 619{
270 int i; 620 unsigned long i;
271 void *symtab_void, *strtab_void; 621 void *symtab_void, *strtab_void;
272 622
273 if (!find_sym) return NULL; 623 if (!find_sym) return NULL;
274 624
275 symtab_void = elf_findsecbyname(elf, ".symtab"); 625 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
276 strtab_void = elf_findsecbyname(elf, ".strtab");
277 626
278 if (symtab_void && strtab_void) { 627 if (symtab_void && strtab_void) {
279#define FIND_SYM(B) \ 628#define FIND_SYM(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \ 629 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 630 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 631 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
283 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 632 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
284 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 633 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
285 char *symname; \ 634 char *symname; \
286 for (i = 0; i < cnt; ++i) { \ 635 for (i = 0; i < cnt; ++i) { \
287 if (sym->st_name) { \ 636 if (sym->st_name) { \
288 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 637 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
289 if (*find_sym == '*') { \ 638 if (*find_sym == '*') { \
290 printf("%s(%s) %5lX %15s %s\n", \ 639 printf("%s(%s) %5lX %15s %s\n", \
291 ((*found_sym == 0) ? "\n\t" : "\t"), \ 640 ((*found_sym == 0) ? "\n\t" : "\t"), \
292 (char *)basename(filename), \ 641 elf->base_filename, \
293 (long)sym->st_size, \ 642 (long)sym->st_size, \
294 (char *)get_elfstttype(sym->st_info), \ 643 (char *)get_elfstttype(sym->st_info), \
295 symname); \ 644 symname); \
296 *found_sym = 1; \ 645 *found_sym = 1; \
297 } else if ((strcmp(find_sym, symname) == 0) || \ 646 } else if ((strcmp(find_sym, symname) == 0) || \
301 ++sym; \ 650 ++sym; \
302 } } 651 } }
303 FIND_SYM(32) 652 FIND_SYM(32)
304 FIND_SYM(64) 653 FIND_SYM(64)
305 } 654 }
655
656 if (be_wewy_wewy_quiet) return NULL;
657
306 if (*find_sym != '*' && *found_sym) 658 if (*find_sym != '*' && *found_sym)
307 return find_sym; 659 return find_sym;
308 if (be_quiet) 660 if (be_quiet)
309 return NULL; 661 return NULL;
310 else 662 else
311 return " - "; 663 return (char *)" - ";
312} 664}
313/* scan an elf file and show all the fun stuff */ 665/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout) 666#define prints(str) write(fileno(stdout), str, strlen(str))
315static void scanelf_file(const char *filename) 667static void scanelf_file(const char *filename)
316{ 668{
317 int i; 669 unsigned long i;
318 char found_pax, found_stack, found_relro, found_textrel, 670 char found_pax, found_phdr, found_relro, found_load, found_textrel,
319 found_rpath, found_needed, found_interp, found_sym, 671 found_rpath, found_needed, found_interp, found_bind, found_soname,
320 found_file; 672 found_sym, found_lib, found_file, found_textrels;
321 elfobj *elf; 673 elfobj *elf;
322 struct stat st; 674 struct stat st;
323 static char *out_buffer = NULL; 675 static char *out_buffer = NULL;
324 static size_t out_len; 676 static size_t out_len;
325 677
327 if (lstat(filename, &st) == -1) { 679 if (lstat(filename, &st) == -1) {
328 if (be_verbose > 2) printf("%s: does not exist\n", filename); 680 if (be_verbose > 2) printf("%s: does not exist\n", filename);
329 return; 681 return;
330 } 682 }
331 /* always handle regular files and handle symlinked files if no -y */ 683 /* always handle regular files and handle symlinked files if no -y */
332 if (!(S_ISREG(st.st_mode) || (S_ISLNK(st.st_mode) && scan_symlink))) { 684 if (S_ISLNK(st.st_mode)) {
685 if (!scan_symlink) return;
686 stat(filename, &st);
687 }
688 if (!S_ISREG(st.st_mode)) {
333 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 689 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
334 return; 690 return;
335 } 691 }
336 692
337 found_pax = found_stack = found_relro = found_textrel = \ 693 found_pax = found_phdr = found_relro = found_load = found_textrel = \
338 found_rpath = found_needed = found_interp = found_sym = \ 694 found_rpath = found_needed = found_interp = found_bind = found_soname = \
339 found_file = 0; 695 found_sym = found_lib = found_file = found_textrels = 0;
340 696
341 /* verify this is real ELF */ 697 /* verify this is real ELF */
342 if ((elf = readelf(filename)) == NULL) { 698 if ((elf = readelf(filename)) == NULL) {
343 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 699 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
344 return; 700 return;
345 } 701 }
346 702
347 if (be_verbose > 1) 703 if (be_verbose > 1)
348 printf("%s: scanning file {%s,%s}\n", filename, 704 printf("%s: scanning file {%s,%s}\n", filename,
349 get_elfeitype(elf, EI_CLASS, elf->elf_class), 705 get_elfeitype(EI_CLASS, elf->elf_class),
350 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA])); 706 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
351 else if (be_verbose) 707 else if (be_verbose)
352 printf("%s: scanning file\n", filename); 708 printf("%s: scanning file\n", filename);
353 709
354 /* init output buffer */ 710 /* init output buffer */
355 if (!out_buffer) { 711 if (!out_buffer) {
358 } 714 }
359 *out_buffer = '\0'; 715 *out_buffer = '\0';
360 716
361 /* show the header */ 717 /* show the header */
362 if (!be_quiet && show_banner) { 718 if (!be_quiet && show_banner) {
363 for (i=0; out_format[i]; ++i) { 719 for (i = 0; out_format[i]; ++i) {
364 if (out_format[i] != '%') continue; 720 if (!IS_MODIFIER(out_format[i])) continue;
365 721
366 switch (out_format[++i]) { 722 switch (out_format[++i]) {
367 case '%': break; 723 case '%': break;
724 case '#': break;
725 case 'F':
726 case 'p':
368 case 'F': prints("FILE "); break; 727 case 'f': prints("FILE "); found_file = 1; break;
369 case 'o': prints(" TYPE "); break; 728 case 'o': prints(" TYPE "); break;
370 case 'x': prints(" PAX "); break; 729 case 'x': prints(" PAX "); break;
371 case 'e': prints("STK/REL "); break; 730 case 'e': prints("STK/REL/PTL "); break;
372 case 't': prints("TEXTREL "); break; 731 case 't': prints("TEXTREL "); break;
373 case 'r': prints("RPATH "); break; 732 case 'r': prints("RPATH "); break;
374 case 'n': prints("NEEDED "); break; 733 case 'n': prints("NEEDED "); break;
375 case 'i': prints("INTERP "); break; 734 case 'i': prints("INTERP "); break;
735 case 'b': prints("BIND "); break;
736 case 'S': prints("SONAME "); break;
376 case 's': prints("SYM "); break; 737 case 's': prints("SYM "); break;
738 case 'N': prints("LIB "); break;
739 case 'T': prints("TEXTRELS "); break;
740 default: warnf("'%c' has no title ?", out_format[i]);
377 } 741 }
378 } 742 }
743 if (!found_file) prints("FILE ");
379 prints("\n"); 744 prints("\n");
745 found_file = 0;
380 show_banner = 0; 746 show_banner = 0;
381 } 747 }
382 748
383 /* dump all the good stuff */ 749 /* dump all the good stuff */
384 for (i=0; out_format[i]; ++i) { 750 for (i = 0; out_format[i]; ++i) {
385 const char *out; 751 const char *out;
752 const char *tmp;
386 753
387 /* make sure we trim leading spaces in quiet mode */ 754 /* make sure we trim leading spaces in quiet mode */
388 if (be_quiet && *out_buffer == ' ' && !out_buffer[1]) 755 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
389 *out_buffer = '\0'; 756 *out_buffer = '\0';
390 757
391 if (out_format[i] != '%') { 758 if (!IS_MODIFIER(out_format[i])) {
392 xchrcat(&out_buffer, out_format[i], &out_len); 759 xchrcat(&out_buffer, out_format[i], &out_len);
393 continue; 760 continue;
394 } 761 }
395 762
396 out = NULL; 763 out = NULL;
764 be_wewy_wewy_quiet = (out_format[i] == '#');
397 switch (out_format[++i]) { 765 switch (out_format[++i]) {
766 case '%':
767 case '#':
398 case '%': xchrcat(&out_buffer, '%', &out_len); break; 768 xchrcat(&out_buffer, out_format[i], &out_len); break;
399 case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break; 769 case 'F':
770 found_file = 1;
771 if (be_wewy_wewy_quiet) break;
772 xstrcat(&out_buffer, filename, &out_len);
773 break;
774 case 'p':
775 found_file = 1;
776 if (be_wewy_wewy_quiet) break;
777 tmp = filename;
778 if (search_path) {
779 ssize_t len_search = strlen(search_path);
780 ssize_t len_file = strlen(filename);
781 if (!strncmp(filename, search_path, len_search) && \
782 len_file > len_search)
783 tmp += len_search;
784 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
785 }
786 xstrcat(&out_buffer, tmp, &out_len);
787 break;
788 case 'f':
789 found_file = 1;
790 if (be_wewy_wewy_quiet) break;
791 tmp = strrchr(filename, '/');
792 tmp = (tmp == NULL ? filename : tmp+1);
793 xstrcat(&out_buffer, tmp, &out_len);
794 break;
400 case 'o': out = get_elfetype(elf); break; 795 case 'o': out = get_elfetype(elf); break;
401 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 796 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
402 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break; 797 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
403 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 798 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
799 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
404 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 800 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
801 case 'n':
405 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break; 802 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
406 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 803 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
804 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
805 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
407 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break; 806 case 's': out = scanelf_file_sym(elf, &found_sym); break;
807 default: warnf("'%c' has no scan code?", out_format[i]);
408 } 808 }
409 if (out) xstrcat(&out_buffer, out, &out_len); 809 if (out) xstrcat(&out_buffer, out, &out_len);
410 } 810 }
411 811
412 if (!found_file) { 812#define FOUND_SOMETHING() \
413 if (!be_quiet || found_pax || found_stack || found_textrel || \ 813 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
414 found_rpath || found_needed || found_interp || found_sym) 814 found_rpath || found_needed || found_interp || found_bind || \
815 found_soname || found_sym || found_lib || found_textrels)
816
817 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
818 xchrcat(&out_buffer, ' ', &out_len);
415 xstrcat(&out_buffer, filename, &out_len); 819 xstrcat(&out_buffer, filename, &out_len);
416 } 820 }
417 if (!(be_quiet && xemptybuffer(out_buffer))) 821 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
418 puts(out_buffer); 822 puts(out_buffer);
823 fflush(stdout);
824 }
419 825
420 unreadelf(elf); 826 unreadelf(elf);
421} 827}
422 828
423/* scan a directory for ET_EXEC files and print when we find one */ 829/* scan a directory for ET_EXEC files and print when we find one */
452 while ((dentry = readdir(dir))) { 858 while ((dentry = readdir(dir))) {
453 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 859 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
454 continue; 860 continue;
455 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 861 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
456 if (len >= sizeof(buf)) { 862 if (len >= sizeof(buf)) {
457 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 863 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
864 (unsigned long)len, (unsigned long)sizeof(buf));
458 continue; 865 continue;
459 } 866 }
460 sprintf(buf, "%s/%s", path, dentry->d_name); 867 sprintf(buf, "%s/%s", path, dentry->d_name);
461 if (lstat(buf, &st) != -1) { 868 if (lstat(buf, &st) != -1) {
462 if (S_ISREG(st.st_mode)) 869 if (S_ISREG(st.st_mode))
468 } 875 }
469 } 876 }
470 closedir(dir); 877 closedir(dir);
471} 878}
472 879
880static int scanelf_from_file(char *filename)
881{
882 FILE *fp = NULL;
883 char *p;
884 char path[_POSIX_PATH_MAX];
885
886 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
887 fp = stdin;
888 else if ((fp = fopen(filename, "r")) == NULL)
889 return 1;
890
891 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
892 if ((p = strchr(path, '\n')) != NULL)
893 *p = 0;
894 search_path = path;
895 scanelf_dir(path);
896 }
897 if (fp != stdin)
898 fclose(fp);
899 return 0;
900}
901
902static void load_ld_so_conf()
903{
904 FILE *fp = NULL;
905 char *p;
906 char path[_POSIX_PATH_MAX];
907 int i = 0;
908
909 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
910 return;
911
912 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
913 if (*path != '/')
914 continue;
915
916 if ((p = strrchr(path, '\r')) != NULL)
917 *p = 0;
918 if ((p = strchr(path, '\n')) != NULL)
919 *p = 0;
920
921 ldpaths[i++] = xstrdup(path);
922
923 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
924 break;
925 }
926 ldpaths[i] = NULL;
927
928 fclose(fp);
929}
930
473/* scan /etc/ld.so.conf for paths */ 931/* scan /etc/ld.so.conf for paths */
474static void scanelf_ldpath() 932static void scanelf_ldpath()
475{ 933{
476 char scan_l, scan_ul, scan_ull; 934 char scan_l, scan_ul, scan_ull;
477 char *path, *p; 935 int i = 0;
478 FILE *fp;
479 936
480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 937 if (!ldpaths[0])
481 err("Unable to open ld.so.conf: %s", strerror(errno)); 938 err("Unable to load any paths from ld.so.conf");
482 939
483 scan_l = scan_ul = scan_ull = 0; 940 scan_l = scan_ul = scan_ull = 0;
484 941
485 path = (char*)xmalloc(_POSIX_PATH_MAX); 942 while (ldpaths[i]) {
486 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
487 if (*path == '/') {
488 if ((p = strrchr(path, '\r')) != NULL)
489 *p = 0;
490 if ((p = strrchr(path, '\n')) != NULL)
491 *p = 0;
492 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1; 943 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
493 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 944 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
494 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 945 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
495 scanelf_dir(path); 946 scanelf_dir(ldpaths[i]);
947 ++i;
496 } 948 }
497 free(path);
498 fclose(fp);
499 949
500 if (!scan_l) scanelf_dir("/lib"); 950 if (!scan_l) scanelf_dir("/lib");
501 if (!scan_ul) scanelf_dir("/usr/lib"); 951 if (!scan_ul) scanelf_dir("/usr/lib");
502 if (!scan_ull) scanelf_dir("/usr/local/lib"); 952 if (!scan_ull) scanelf_dir("/usr/local/lib");
503} 953}
521} 971}
522 972
523 973
524 974
525/* usage / invocation handling functions */ 975/* usage / invocation handling functions */
526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 976#define PARSE_FLAGS "plRmyxetrnibSs:gN:TaqvF:f:o:BhV"
527#define a_argument required_argument 977#define a_argument required_argument
528static struct option const long_opts[] = { 978static struct option const long_opts[] = {
529 {"path", no_argument, NULL, 'p'}, 979 {"path", no_argument, NULL, 'p'},
530 {"ldpath", no_argument, NULL, 'l'}, 980 {"ldpath", no_argument, NULL, 'l'},
531 {"recursive", no_argument, NULL, 'R'}, 981 {"recursive", no_argument, NULL, 'R'},
535 {"header", no_argument, NULL, 'e'}, 985 {"header", no_argument, NULL, 'e'},
536 {"textrel", no_argument, NULL, 't'}, 986 {"textrel", no_argument, NULL, 't'},
537 {"rpath", no_argument, NULL, 'r'}, 987 {"rpath", no_argument, NULL, 'r'},
538 {"needed", no_argument, NULL, 'n'}, 988 {"needed", no_argument, NULL, 'n'},
539 {"interp", no_argument, NULL, 'i'}, 989 {"interp", no_argument, NULL, 'i'},
990 {"bind", no_argument, NULL, 'b'},
991 {"soname", no_argument, NULL, 'S'},
540 {"symbol", a_argument, NULL, 's'}, 992 {"symbol", a_argument, NULL, 's'},
993 {"lib", a_argument, NULL, 'N'},
994 {"gmatch", no_argument, NULL, 'g'},
995 {"textrels", no_argument, NULL, 'T'},
541 {"all", no_argument, NULL, 'a'}, 996 {"all", no_argument, NULL, 'a'},
542 {"quiet", no_argument, NULL, 'q'}, 997 {"quiet", no_argument, NULL, 'q'},
543 {"verbose", no_argument, NULL, 'v'}, 998 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'}, 999 {"format", a_argument, NULL, 'F'},
1000 {"from", a_argument, NULL, 'f'},
545 {"file", a_argument, NULL, 'o'}, 1001 {"file", a_argument, NULL, 'o'},
546 {"nobanner", no_argument, NULL, 'B'}, 1002 {"nobanner", no_argument, NULL, 'B'},
547 {"help", no_argument, NULL, 'h'}, 1003 {"help", no_argument, NULL, 'h'},
548 {"version", no_argument, NULL, 'V'}, 1004 {"version", no_argument, NULL, 'V'},
549 {NULL, no_argument, NULL, 0x0} 1005 {NULL, no_argument, NULL, 0x0}
550}; 1006};
1007
551static char *opts_help[] = { 1008static const char *opts_help[] = {
552 "Scan all directories in PATH environment", 1009 "Scan all directories in PATH environment",
553 "Scan all directories in /etc/ld.so.conf", 1010 "Scan all directories in /etc/ld.so.conf",
554 "Scan directories recursively", 1011 "Scan directories recursively",
555 "Don't recursively cross mount points", 1012 "Don't recursively cross mount points",
556 "Don't scan symlinks\n", 1013 "Don't scan symlinks\n",
557 "Print PaX markings", 1014 "Print PaX markings",
558 "Print GNU_STACK markings", 1015 "Print GNU_STACK/PT_LOAD markings",
559 "Print TEXTREL information", 1016 "Print TEXTREL information",
560 "Print RPATH information", 1017 "Print RPATH information",
561 "Print NEEDED information", 1018 "Print NEEDED information",
562 "Print INTERP information", 1019 "Print INTERP information",
1020 "Print BIND information",
1021 "Print SONAME information",
563 "Find a specified symbol", 1022 "Find a specified symbol",
1023 "Find a specified library",
1024 "Use strncmp to match libraries. (use with -N)",
1025 "Locate cause of TEXTREL",
564 "Print all scanned info (-x -e -t -r)\n", 1026 "Print all scanned info (-x -e -t -r -b)\n",
565 "Only output 'bad' things", 1027 "Only output 'bad' things",
566 "Be verbose (can be specified more than once)", 1028 "Be verbose (can be specified more than once)",
567 "Use specified format for output", 1029 "Use specified format for output",
1030 "Read input stream from a filename",
568 "Write output stream to a filename", 1031 "Write output stream to a filename",
569 "Don't display the header", 1032 "Don't display the header",
570 "Print this help and exit", 1033 "Print this help and exit",
571 "Print version and exit", 1034 "Print version and exit",
572 NULL 1035 NULL
573}; 1036};
574 1037
575/* display usage and exit */ 1038/* display usage and exit */
576static void usage(int status) 1039static void usage(int status)
577{ 1040{
578 int i; 1041 unsigned long i;
579 printf(" Scan ELF binaries for stuff\n\n" 1042 printf("* Scan ELF binaries for stuff\n\n"
580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1043 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
581 printf("Options: -[%s]\n", PARSE_FLAGS); 1044 printf("Options: -[%s]\n", PARSE_FLAGS);
582 for (i = 0; long_opts[i].name; ++i) 1045 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument) 1046 if (long_opts[i].has_arg == no_argument)
584 printf(" -%c, --%-13s %s\n", long_opts[i].val, 1047 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
585 long_opts[i].name, opts_help[i]); 1048 long_opts[i].name, opts_help[i]);
586 else 1049 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 1050 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
588 long_opts[i].name, opts_help[i]); 1051 long_opts[i].name, opts_help[i]);
1052
1053 if (status != EXIT_SUCCESS)
1054 exit(status);
1055
1056 puts("\nThe format modifiers for the -F option are:");
1057 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1058 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1059 puts(" i INTERP \tb BIND \ts symbol");
1060 puts(" N library \to Type \tT TEXTRELs");
1061 puts(" S SONAME");
1062 puts(" p filename (with search path removed)");
1063 puts(" f filename (short name/basename)");
1064 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1065
589 exit(status); 1066 exit(status);
590} 1067}
591 1068
592/* parse command line arguments and preform needed actions */ 1069/* parse command line arguments and preform needed actions */
593static void parseargs(int argc, char *argv[]) 1070static void parseargs(int argc, char *argv[])
594{ 1071{
595 int flag; 1072 int i;
1073 char *from_file = NULL;
596 1074
597 opterr = 0; 1075 opterr = 0;
598 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1076 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
599 switch (flag) { 1077 switch (i) {
600 1078
601 case 'V': 1079 case 'V':
602 printf("%s compiled %s\n%s\n" 1080 printf("pax-utils-%s: %s compiled %s\n%s\n"
603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1081 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
604 __FILE__, __DATE__, rcsid, argv0); 1082 VERSION, __FILE__, __DATE__, rcsid, argv0);
605 exit(EXIT_SUCCESS); 1083 exit(EXIT_SUCCESS);
606 break; 1084 break;
607 case 'h': usage(EXIT_SUCCESS); break; 1085 case 'h': usage(EXIT_SUCCESS); break;
608 1086 case 'f':
1087 if (from_file) err("Don't specify -f twice");
1088 from_file = xstrdup(optarg);
1089 break;
609 case 'o': { 1090 case 'o': {
610 FILE *fp = NULL; 1091 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout); 1092 if ((fp = freopen(optarg, "w", stdout)) == NULL)
612 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1093 err("Could not open output stream '%s': %s", optarg, strerror(errno));
614 stdout = fp; 1094 SET_STDOUT(fp);
615 break; 1095 break;
616 } 1096 }
617 1097
618 case 's': { 1098 case 's': {
619 size_t len; 1099 size_t len;
1100 if (find_sym) err("Don't specify -s twice");
620 find_sym = xstrdup(optarg); 1101 find_sym = xstrdup(optarg);
621 len = strlen(find_sym) + 1; 1102 len = strlen(find_sym) + 1;
622 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1103 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
623 sprintf(versioned_symname, "%s@", find_sym); 1104 sprintf(versioned_symname, "%s@", find_sym);
624 break; 1105 break;
625 } 1106 }
1107 case 'N': {
1108 if (find_lib) err("Don't specify -N twice");
1109 find_lib = xstrdup(optarg);
1110 break;
1111 }
626 1112
627 case 'F': { 1113 case 'F': {
1114 if (out_format) err("Don't specify -F twice");
628 out_format = strdup(optarg); 1115 out_format = xstrdup(optarg);
629 break; 1116 break;
630 } 1117 }
631 1118
1119 case 'g': gmatch = 1;
632 case 'y': scan_symlink = 0; break; 1120 case 'y': scan_symlink = 0; break;
633 case 'B': show_banner = 0; break; 1121 case 'B': show_banner = 0; break;
634 case 'l': scan_ldpath = 1; break; 1122 case 'l': scan_ldpath = 1; break;
635 case 'p': scan_envpath = 1; break; 1123 case 'p': scan_envpath = 1; break;
636 case 'R': dir_recurse = 1; break; 1124 case 'R': dir_recurse = 1; break;
637 case 'm': dir_crossmount = 0; break; 1125 case 'm': dir_crossmount = 0; break;
638 case 'x': show_pax = 1; break; 1126 case 'x': show_pax = 1; break;
639 case 'e': show_stack = 1; break; 1127 case 'e': show_phdr = 1; break;
640 case 't': show_textrel = 1; break; 1128 case 't': show_textrel = 1; break;
641 case 'r': show_rpath = 1; break; 1129 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break; 1130 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break; 1131 case 'i': show_interp = 1; break;
1132 case 'b': show_bind = 1; break;
1133 case 'S': show_soname = 1; break;
1134 case 'T': show_textrels = 1; break;
644 case 'q': be_quiet = 1; break; 1135 case 'q': be_quiet = 1; break;
645 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1136 case 'v': be_verbose = (be_verbose % 20) + 1; break;
646 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break; 1137 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
647 1138
648 case ':': 1139 case ':':
649 warn("Option missing parameter\n"); 1140 err("Option missing parameter\n");
650 usage(EXIT_FAILURE);
651 break;
652 case '?': 1141 case '?':
653 warn("Unknown option\n"); 1142 err("Unknown option\n");
654 usage(EXIT_FAILURE);
655 break;
656 default: 1143 default:
657 err("Unhandled option '%c'", flag); 1144 err("Unhandled option '%c'", i);
658 break;
659 }
660 } 1145 }
661 1146 }
662 if (be_quiet && be_verbose)
663 err("You can be quiet or you can be verbose, not both, stupid");
664 1147
665 /* let the format option override all other options */ 1148 /* let the format option override all other options */
666 if (out_format) { 1149 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 1150 show_pax = show_phdr = show_textrel = show_rpath = \
1151 show_needed = show_interp = show_bind = show_soname = \
1152 show_textrels = 0;
668 for (flag=0; out_format[flag]; ++flag) { 1153 for (i = 0; out_format[i]; ++i) {
669 if (out_format[flag] != '%') continue; 1154 if (!IS_MODIFIER(out_format[i])) continue;
670 1155
671 switch (out_format[++flag]) { 1156 switch (out_format[++i]) {
672 case '%': break; 1157 case '%': break;
1158 case '#': break;
673 case 'F': break; 1159 case 'F': break;
1160 case 'p': break;
1161 case 'f': break;
674 case 's': break; 1162 case 's': break;
1163 case 'N': break;
675 case 'o': break; 1164 case 'o': break;
676 case 'x': show_pax = 1; break; 1165 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break; 1166 case 'e': show_phdr = 1; break;
678 case 't': show_textrel = 1; break; 1167 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break; 1168 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break; 1169 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 1; break; 1170 case 'i': show_interp = 1; break;
1171 case 'b': show_bind = 1; break;
1172 case 'S': show_soname = 1; break;
1173 case 'T': show_textrels = 1; break;
682 default: 1174 default:
683 err("Invalid format specifier '%c' (byte %i)", 1175 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1); 1176 out_format[i], i+1);
685 } 1177 }
686 } 1178 }
687 1179
688 /* construct our default format */ 1180 /* construct our default format */
689 } else { 1181 } else {
690 size_t fmt_len = 30; 1182 size_t fmt_len = 30;
691 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1183 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
692 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1184 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
693 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1185 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 1186 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1187 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1188 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1189 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1190 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1191 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1192 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1193 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1194 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1195 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1196 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 } 1197 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format); 1198 if (be_verbose > 2) printf("Format: %s\n", out_format);
703 1199
704 /* now lets actually do the scanning */ 1200 /* now lets actually do the scanning */
1201 if (scan_ldpath || (show_rpath && be_quiet))
1202 load_ld_so_conf();
705 if (scan_ldpath) scanelf_ldpath(); 1203 if (scan_ldpath) scanelf_ldpath();
706 if (scan_envpath) scanelf_envpath(); 1204 if (scan_envpath) scanelf_envpath();
1205 if (from_file) {
1206 scanelf_from_file(from_file);
1207 free(from_file);
1208 from_file = *argv;
1209 }
707 if (optind == argc && !scan_ldpath && !scan_envpath) 1210 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
708 err("Nothing to scan !?"); 1211 err("Nothing to scan !?");
709 while (optind < argc) 1212 while (optind < argc) {
710 scanelf_dir(argv[optind++]); 1213 search_path = argv[optind++];
1214 scanelf_dir(search_path);
1215 }
711 1216
712 /* clean up */ 1217 /* clean up */
713 if (find_sym) { 1218 if (find_sym) {
714 free(find_sym); 1219 free(find_sym);
715 free(versioned_symname); 1220 free(versioned_symname);
716 } 1221 }
1222 if (find_lib) free(find_lib);
717 if (out_format) free(out_format); 1223 if (out_format) free(out_format);
1224 for (i = 0; ldpaths[i]; ++i)
1225 free(ldpaths[i]);
718} 1226}
719 1227
720 1228
721 1229
722/* utility funcs */ 1230/* utility funcs */
723static char *xstrdup(char *s) 1231static char *xstrdup(const char *s)
724{ 1232{
725 char *ret = strdup(s); 1233 char *ret = strdup(s);
726 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1234 if (!ret) err("Could not strdup(): %s", strerror(errno));
727 return ret; 1235 return ret;
728} 1236}
1237
729static void *xmalloc(size_t size) 1238static void *xmalloc(size_t size)
730{ 1239{
731 void *ret = malloc(size); 1240 void *ret = malloc(size);
732 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1241 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
733 return ret; 1242 return ret;
734} 1243}
1244
735static void xstrcat(char **dst, const char *src, size_t *curr_len) 1245static void xstrcat(char **dst, const char *src, size_t *curr_len)
736{ 1246{
737 long new_len; 1247 size_t new_len;
738 1248
739 new_len = strlen(*dst) + strlen(src); 1249 new_len = strlen(*dst) + strlen(src);
740 if (*curr_len <= new_len) { 1250 if (*curr_len <= new_len) {
741 *curr_len = new_len + (*curr_len / 2); 1251 *curr_len = new_len + (*curr_len / 2);
742 *dst = realloc(*dst, *curr_len); 1252 *dst = realloc(*dst, *curr_len);
744 err("could not realloc %li bytes", (unsigned long)*curr_len); 1254 err("could not realloc %li bytes", (unsigned long)*curr_len);
745 } 1255 }
746 1256
747 strcat(*dst, src); 1257 strcat(*dst, src);
748} 1258}
1259
749static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1260static inline void xchrcat(char **dst, const char append, size_t *curr_len)
750{ 1261{
751 static char my_app[2]; 1262 static char my_app[2];
752 my_app[0] = append; 1263 my_app[0] = append;
753 my_app[1] = '\0'; 1264 my_app[1] = '\0';
754 xstrcat(dst, my_app, curr_len); 1265 xstrcat(dst, my_app, curr_len);
755} 1266}
756static int xemptybuffer(const char *buff)
757{
758 long i;
759 for (i=0; buff[i]; ++i)
760 if (buff[i] != ' ')
761 return 0;
762 return 1;
763}
764 1267
765 1268
766 1269
767int main(int argc, char *argv[]) 1270int main(int argc, char *argv[])
768{ 1271{
769 if (argc < 2) 1272 if (argc < 2)
770 usage(EXIT_FAILURE); 1273 usage(EXIT_FAILURE);
771 parseargs(argc, argv); 1274 parseargs(argc, argv);
772 fclose(stdout); 1275 fclose(stdout);
1276#ifdef __BOUNDS_CHECKING_ON
1277 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
1278#endif
773 return EXIT_SUCCESS; 1279 return EXIT_SUCCESS;
774} 1280}

Legend:
Removed from v.1.43  
changed lines
  Added in v.1.90

  ViewVC Help
Powered by ViewVC 1.1.20