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

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

  ViewVC Help
Powered by ViewVC 1.1.20