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

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

  ViewVC Help
Powered by ViewVC 1.1.20