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

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

  ViewVC Help
Powered by ViewVC 1.1.20