1 | /* |
1 | /* |
2 | * Copyright 2003-2005 Gentoo Foundation |
2 | * Copyright 2003-2005 Gentoo Foundation |
3 | * Distributed under the terms of the GNU General Public License v2 |
3 | * Distributed under the terms of the GNU General Public License v2 |
4 | * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.75 2005/06/06 23:32:38 vapier Exp $ |
4 | * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.76 2005/06/08 04:24:19 vapier Exp $ |
5 | * |
5 | * |
6 | ******************************************************************** |
6 | ******************************************************************** |
7 | * This program is free software; you can redistribute it and/or |
7 | * This program is free software; you can redistribute it and/or |
8 | * 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 |
9 | * published by the Free Software Foundation; either version 2 of the |
9 | * published by the Free Software Foundation; either version 2 of the |
… | |
… | |
33 | #include <dirent.h> |
33 | #include <dirent.h> |
34 | #include <getopt.h> |
34 | #include <getopt.h> |
35 | #include <assert.h> |
35 | #include <assert.h> |
36 | #include "paxelf.h" |
36 | #include "paxelf.h" |
37 | |
37 | |
38 | static const char *rcsid = "$Id: scanelf.c,v 1.75 2005/06/06 23:32:38 vapier Exp $"; |
38 | static const char *rcsid = "$Id: scanelf.c,v 1.76 2005/06/08 04:24:19 vapier Exp $"; |
39 | #define argv0 "scanelf" |
39 | #define argv0 "scanelf" |
40 | |
40 | |
41 | #define IS_MODIFIER(c) (c == '%' || c == '#') |
41 | #define IS_MODIFIER(c) (c == '%' || c == '#') |
42 | |
42 | |
43 | |
43 | |
… | |
… | |
66 | static char show_textrel = 0; |
66 | static char show_textrel = 0; |
67 | static char show_rpath = 0; |
67 | static char show_rpath = 0; |
68 | static char show_needed = 0; |
68 | static char show_needed = 0; |
69 | static char show_interp = 0; |
69 | static char show_interp = 0; |
70 | static char show_bind = 0; |
70 | static char show_bind = 0; |
|
|
71 | static char show_textrels = 0; |
71 | static char show_banner = 1; |
72 | static char show_banner = 1; |
72 | static char be_quiet = 0; |
73 | static char be_quiet = 0; |
73 | static char be_verbose = 0; |
74 | static char be_verbose = 0; |
74 | static char be_wewy_wewy_quiet = 0; |
75 | static char be_wewy_wewy_quiet = 0; |
75 | static char *find_sym = NULL, *versioned_symname = NULL; |
76 | static char *find_sym = NULL, *versioned_symname = NULL; |
… | |
… | |
217 | |
218 | |
218 | if (be_quiet || be_wewy_wewy_quiet) |
219 | if (be_quiet || be_wewy_wewy_quiet) |
219 | return NULL; |
220 | return NULL; |
220 | else |
221 | else |
221 | return (char *)" - "; |
222 | return (char *)" - "; |
|
|
223 | } |
|
|
224 | static char *scanelf_file_textrels(elfobj *elf, char *found_textrels) |
|
|
225 | { |
|
|
226 | /* To locate TEXTREL symbols: |
|
|
227 | * for each shdr of type SHT_REL: |
|
|
228 | * for each phdr of type PT_LOAD: |
|
|
229 | * if phdr is not writable (why?) |
|
|
230 | * if shdr offset is inside of load (shdr->offset, phdr->{vaddr,memsz} |
|
|
231 | * look up shdr's symbol name |
|
|
232 | */ |
|
|
233 | unsigned long p, s, r, rmax; |
|
|
234 | char *symtab_void, *strtab_void; |
|
|
235 | |
|
|
236 | if (!show_textrels) return NULL; |
|
|
237 | |
|
|
238 | /* debug sections */ |
|
|
239 | symtab_void = elf_findsecbyname(elf, ".symtab"); |
|
|
240 | strtab_void = elf_findsecbyname(elf, ".strtab"); |
|
|
241 | /* fall back to runtime sections */ |
|
|
242 | if (!symtab_void || !strtab_void) { |
|
|
243 | symtab_void = elf_findsecbyname(elf, ".dynsym"); |
|
|
244 | strtab_void = elf_findsecbyname(elf, ".dynstr"); |
|
|
245 | } |
|
|
246 | |
|
|
247 | if (elf->phdr && elf->shdr) { |
|
|
248 | #define SHOW_TEXTRELS(B) \ |
|
|
249 | if (elf->elf_class == ELFCLASS ## B) { \ |
|
|
250 | Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ |
|
|
251 | Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ |
|
|
252 | Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ |
|
|
253 | Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ |
|
|
254 | Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ |
|
|
255 | Elf ## B ## _Rel *rel; \ |
|
|
256 | Elf ## B ## _Rela *rela; \ |
|
|
257 | /* search the section headers for relocations */ \ |
|
|
258 | for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \ |
|
|
259 | uint32_t sh_type = EGET(shdr[s].sh_type); \ |
|
|
260 | if (sh_type == SHT_REL) { \ |
|
|
261 | rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \ |
|
|
262 | rela = NULL; \ |
|
|
263 | rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \ |
|
|
264 | } else if (sh_type == SHT_RELA) { \ |
|
|
265 | rel = NULL; \ |
|
|
266 | rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \ |
|
|
267 | rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \ |
|
|
268 | } else \ |
|
|
269 | continue; \ |
|
|
270 | /* search the program headers for PT_LOAD headers */ \ |
|
|
271 | for (p = 0; p < EGET(ehdr->e_phnum); ++p) { \ |
|
|
272 | Elf ## B ## _Addr vaddr; \ |
|
|
273 | uint ## B ## _t memsz; \ |
|
|
274 | if (EGET(phdr[p].p_type) != PT_LOAD) continue; \ |
|
|
275 | if (EGET(phdr[p].p_flags) & PF_W) continue; \ |
|
|
276 | vaddr = EGET(phdr[p].p_vaddr); \ |
|
|
277 | memsz = EGET(phdr[p].p_memsz); \ |
|
|
278 | *found_textrels = 1; \ |
|
|
279 | /* now see if any of the relocs are in the PT_LOAD */ \ |
|
|
280 | for (r = 0; r < rmax; ++r) { \ |
|
|
281 | unsigned long sym_max; \ |
|
|
282 | Elf ## B ## _Addr offset_tmp; \ |
|
|
283 | Elf ## B ## _Sym *func; \ |
|
|
284 | Elf ## B ## _Sym *sym; \ |
|
|
285 | Elf ## B ## _Addr r_offset; \ |
|
|
286 | uint ## B ## _t r_info; \ |
|
|
287 | if (sh_type == SHT_REL) { \ |
|
|
288 | r_offset = EGET(rel[r].r_offset); \ |
|
|
289 | r_info = EGET(rel[r].r_info); \ |
|
|
290 | } else { \ |
|
|
291 | r_offset = EGET(rela[r].r_offset); \ |
|
|
292 | r_info = EGET(rela[r].r_info); \ |
|
|
293 | } \ |
|
|
294 | /* make sure this relocation is inside of the .text */ \ |
|
|
295 | if (r_offset < vaddr || r_offset >= vaddr + memsz) continue; \ |
|
|
296 | sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ |
|
|
297 | /* locate this relocation symbol name */ \ |
|
|
298 | sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ |
|
|
299 | sym += ELF ## B ## _R_SYM(r_info); \ |
|
|
300 | /* show the raw details about this reloc */ \ |
|
|
301 | printf("\tTEXTREL %s: ", elf->base_filename); \ |
|
|
302 | if (sym->st_name) \ |
|
|
303 | printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \ |
|
|
304 | else \ |
|
|
305 | printf("(NULL: fake?)"); \ |
|
|
306 | printf(" [0x%lX]", (unsigned long)r_offset); \ |
|
|
307 | /* now try to find the closest symbol that this rel is probably in */ \ |
|
|
308 | sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ |
|
|
309 | func = NULL; \ |
|
|
310 | offset_tmp = 0; \ |
|
|
311 | while (sym_max--) { \ |
|
|
312 | if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \ |
|
|
313 | func = sym; \ |
|
|
314 | offset_tmp = EGET(sym->st_value); \ |
|
|
315 | } \ |
|
|
316 | ++sym; \ |
|
|
317 | } \ |
|
|
318 | printf(" in "); \ |
|
|
319 | if (func && func->st_name) \ |
|
|
320 | printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \ |
|
|
321 | else \ |
|
|
322 | printf("(NULL: fake?)"); \ |
|
|
323 | printf(" [0x%lX]\n", (unsigned long)offset_tmp); \ |
|
|
324 | } \ |
|
|
325 | } \ |
|
|
326 | } } |
|
|
327 | SHOW_TEXTRELS(32) |
|
|
328 | SHOW_TEXTRELS(64) |
|
|
329 | } |
|
|
330 | |
|
|
331 | return NULL; |
222 | } |
332 | } |
223 | static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) |
333 | static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) |
224 | { |
334 | { |
225 | unsigned long i, s; |
335 | unsigned long i, s; |
226 | char *rpath, *runpath, **r; |
336 | char *rpath, *runpath, **r; |
… | |
… | |
442 | symtab_void = elf_findsecbyname(elf, ".dynsym"); |
552 | symtab_void = elf_findsecbyname(elf, ".dynsym"); |
443 | strtab_void = elf_findsecbyname(elf, ".dynstr"); |
553 | strtab_void = elf_findsecbyname(elf, ".dynstr"); |
444 | } |
554 | } |
445 | |
555 | |
446 | if (symtab_void && strtab_void) { |
556 | if (symtab_void && strtab_void) { |
447 | char *base, *basemem; |
|
|
448 | basemem = xstrdup(elf->filename); |
|
|
449 | base = basename(basemem); |
|
|
450 | #define FIND_SYM(B) \ |
557 | #define FIND_SYM(B) \ |
451 | if (elf->elf_class == ELFCLASS ## B) { \ |
558 | if (elf->elf_class == ELFCLASS ## B) { \ |
452 | Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ |
559 | Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ |
453 | Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ |
560 | Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ |
454 | Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ |
561 | Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ |
… | |
… | |
458 | if (sym->st_name) { \ |
565 | if (sym->st_name) { \ |
459 | symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ |
566 | symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ |
460 | if (*find_sym == '*') { \ |
567 | if (*find_sym == '*') { \ |
461 | printf("%s(%s) %5lX %15s %s\n", \ |
568 | printf("%s(%s) %5lX %15s %s\n", \ |
462 | ((*found_sym == 0) ? "\n\t" : "\t"), \ |
569 | ((*found_sym == 0) ? "\n\t" : "\t"), \ |
463 | base, \ |
570 | elf->base_filename, \ |
464 | (long)sym->st_size, \ |
571 | (long)sym->st_size, \ |
465 | (char *)get_elfstttype(sym->st_info), \ |
572 | (char *)get_elfstttype(sym->st_info), \ |
466 | symname); \ |
573 | symname); \ |
467 | *found_sym = 1; \ |
574 | *found_sym = 1; \ |
468 | } else if ((strcmp(find_sym, symname) == 0) || \ |
575 | } else if ((strcmp(find_sym, symname) == 0) || \ |
… | |
… | |
471 | } \ |
578 | } \ |
472 | ++sym; \ |
579 | ++sym; \ |
473 | } } |
580 | } } |
474 | FIND_SYM(32) |
581 | FIND_SYM(32) |
475 | FIND_SYM(64) |
582 | FIND_SYM(64) |
476 | free(basemem); |
|
|
477 | } |
583 | } |
478 | |
584 | |
479 | if (be_wewy_wewy_quiet) return NULL; |
585 | if (be_wewy_wewy_quiet) return NULL; |
480 | |
586 | |
481 | if (*find_sym != '*' && *found_sym) |
587 | if (*find_sym != '*' && *found_sym) |
… | |
… | |
490 | static void scanelf_file(const char *filename) |
596 | static void scanelf_file(const char *filename) |
491 | { |
597 | { |
492 | unsigned long i; |
598 | unsigned long i; |
493 | char found_pax, found_phdr, found_relro, found_load, found_textrel, |
599 | char found_pax, found_phdr, found_relro, found_load, found_textrel, |
494 | found_rpath, found_needed, found_interp, found_bind, |
600 | found_rpath, found_needed, found_interp, found_bind, |
495 | found_sym, found_lib, found_file; |
601 | found_sym, found_lib, found_file, found_textrels; |
496 | elfobj *elf; |
602 | elfobj *elf; |
497 | struct stat st; |
603 | struct stat st; |
498 | static char *out_buffer = NULL; |
604 | static char *out_buffer = NULL; |
499 | static size_t out_len; |
605 | static size_t out_len; |
500 | |
606 | |
… | |
… | |
511 | if (!S_ISREG(st.st_mode)) { |
617 | if (!S_ISREG(st.st_mode)) { |
512 | if (be_verbose > 2) printf("%s: skipping non-file\n", filename); |
618 | if (be_verbose > 2) printf("%s: skipping non-file\n", filename); |
513 | return; |
619 | return; |
514 | } |
620 | } |
515 | |
621 | |
516 | found_pax = found_phdr = found_relro = found_load = \ |
622 | found_pax = found_phdr = found_relro = found_load = found_textrel = \ |
517 | found_textrel = found_rpath = found_needed = found_interp = \ |
623 | found_rpath = found_needed = found_interp = found_bind = \ |
518 | found_bind = found_sym = found_lib = found_file = 0; |
624 | found_sym = found_lib = found_file = found_textrels = 0; |
519 | |
625 | |
520 | /* verify this is real ELF */ |
626 | /* verify this is real ELF */ |
521 | if ((elf = readelf(filename)) == NULL) { |
627 | if ((elf = readelf(filename)) == NULL) { |
522 | if (be_verbose > 2) printf("%s: not an ELF\n", filename); |
628 | if (be_verbose > 2) printf("%s: not an ELF\n", filename); |
523 | return; |
629 | return; |
… | |
… | |
556 | case 'n': prints("NEEDED "); break; |
662 | case 'n': prints("NEEDED "); break; |
557 | case 'i': prints("INTERP "); break; |
663 | case 'i': prints("INTERP "); break; |
558 | case 'b': prints("BIND "); break; |
664 | case 'b': prints("BIND "); break; |
559 | case 's': prints("SYM "); break; |
665 | case 's': prints("SYM "); break; |
560 | case 'N': prints("LIB "); break; |
666 | case 'N': prints("LIB "); break; |
|
|
667 | case 'T': prints("TEXTRELS "); break; |
|
|
668 | default: warnf("'%c' has no title ?", out_format[i]); |
561 | } |
669 | } |
562 | } |
670 | } |
563 | if (!found_file) prints("FILE "); |
671 | if (!found_file) prints("FILE "); |
564 | prints("\n"); |
672 | prints("\n"); |
565 | found_file = 0; |
673 | found_file = 0; |
… | |
… | |
585 | switch (out_format[++i]) { |
693 | switch (out_format[++i]) { |
586 | case '%': |
694 | case '%': |
587 | case '#': |
695 | case '#': |
588 | xchrcat(&out_buffer, out_format[i], &out_len); break; |
696 | xchrcat(&out_buffer, out_format[i], &out_len); break; |
589 | case 'F': |
697 | case 'F': |
|
|
698 | found_file = 1; |
590 | if (be_wewy_wewy_quiet) break; |
699 | if (be_wewy_wewy_quiet) break; |
591 | found_file = 1; |
|
|
592 | xstrcat(&out_buffer, filename, &out_len); |
700 | xstrcat(&out_buffer, filename, &out_len); |
593 | break; |
701 | break; |
594 | case 'p': |
702 | case 'p': |
|
|
703 | found_file = 1; |
595 | if (be_wewy_wewy_quiet) break; |
704 | if (be_wewy_wewy_quiet) break; |
596 | found_file = 1; |
|
|
597 | tmp = filename; |
705 | tmp = filename; |
598 | if (search_path) { |
706 | if (search_path) { |
599 | ssize_t len_search = strlen(search_path); |
707 | ssize_t len_search = strlen(search_path); |
600 | ssize_t len_file = strlen(filename); |
708 | ssize_t len_file = strlen(filename); |
601 | if (!strncmp(filename, search_path, len_search) && \ |
709 | if (!strncmp(filename, search_path, len_search) && \ |
… | |
… | |
604 | if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; |
712 | if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; |
605 | } |
713 | } |
606 | xstrcat(&out_buffer, tmp, &out_len); |
714 | xstrcat(&out_buffer, tmp, &out_len); |
607 | break; |
715 | break; |
608 | case 'f': |
716 | case 'f': |
|
|
717 | found_file = 1; |
609 | if (be_wewy_wewy_quiet) break; |
718 | if (be_wewy_wewy_quiet) break; |
610 | found_file = 1; |
|
|
611 | tmp = strrchr(filename, '/'); |
719 | tmp = strrchr(filename, '/'); |
612 | tmp = (tmp == NULL ? filename : tmp+1); |
720 | tmp = (tmp == NULL ? filename : tmp+1); |
613 | xstrcat(&out_buffer, tmp, &out_len); |
721 | xstrcat(&out_buffer, tmp, &out_len); |
614 | break; |
722 | break; |
615 | case 'o': out = get_elfetype(elf); break; |
723 | case 'o': out = get_elfetype(elf); break; |
616 | case 'x': out = scanelf_file_pax(elf, &found_pax); break; |
724 | case 'x': out = scanelf_file_pax(elf, &found_pax); break; |
617 | case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; |
725 | case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; |
618 | case 't': out = scanelf_file_textrel(elf, &found_textrel); break; |
726 | case 't': out = scanelf_file_textrel(elf, &found_textrel); break; |
|
|
727 | case 'T': out = scanelf_file_textrels(elf, &found_textrels); break; |
619 | case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; |
728 | case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; |
620 | case 'n': |
729 | case 'n': |
621 | case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; |
730 | case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; |
622 | case 'i': out = scanelf_file_interp(elf, &found_interp); break; |
731 | case 'i': out = scanelf_file_interp(elf, &found_interp); break; |
623 | case 'b': out = scanelf_file_bind(elf, &found_bind); break; |
732 | case 'b': out = scanelf_file_bind(elf, &found_bind); break; |
624 | case 's': out = scanelf_file_sym(elf, &found_sym); break; |
733 | case 's': out = scanelf_file_sym(elf, &found_sym); break; |
|
|
734 | default: warnf("'%c' has no scan code?", out_format[i]); |
625 | } |
735 | } |
626 | if (out) xstrcat(&out_buffer, out, &out_len); |
736 | if (out) xstrcat(&out_buffer, out, &out_len); |
627 | } |
737 | } |
628 | |
738 | |
629 | #define FOUND_SOMETHING() \ |
739 | #define FOUND_SOMETHING() \ |
630 | (found_pax || found_phdr || found_relro || found_load || found_textrel || \ |
740 | (found_pax || found_phdr || found_relro || found_load || found_textrel || \ |
631 | found_rpath || found_needed || found_interp || found_bind || found_sym || found_lib) |
741 | found_rpath || found_needed || found_interp || found_bind || \ |
|
|
742 | found_sym || found_lib || found_textrels) |
632 | |
743 | |
633 | if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { |
744 | if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { |
634 | xchrcat(&out_buffer, ' ', &out_len); |
745 | xchrcat(&out_buffer, ' ', &out_len); |
635 | xstrcat(&out_buffer, filename, &out_len); |
746 | xstrcat(&out_buffer, filename, &out_len); |
636 | } |
747 | } |
… | |
… | |
672 | while ((dentry = readdir(dir))) { |
783 | while ((dentry = readdir(dir))) { |
673 | if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) |
784 | if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) |
674 | continue; |
785 | continue; |
675 | len = (pathlen + 1 + strlen(dentry->d_name) + 1); |
786 | len = (pathlen + 1 + strlen(dentry->d_name) + 1); |
676 | if (len >= sizeof(buf)) { |
787 | if (len >= sizeof(buf)) { |
677 | warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, len, sizeof(buf)); |
788 | warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, |
|
|
789 | (unsigned long)len, (unsigned long)sizeof(buf)); |
678 | continue; |
790 | continue; |
679 | } |
791 | } |
680 | sprintf(buf, "%s/%s", path, dentry->d_name); |
792 | sprintf(buf, "%s/%s", path, dentry->d_name); |
681 | if (lstat(buf, &st) != -1) { |
793 | if (lstat(buf, &st) != -1) { |
682 | if (S_ISREG(st.st_mode)) |
794 | if (S_ISREG(st.st_mode)) |
… | |
… | |
784 | } |
896 | } |
785 | |
897 | |
786 | |
898 | |
787 | |
899 | |
788 | /* usage / invocation handling functions */ |
900 | /* usage / invocation handling functions */ |
789 | #define PARSE_FLAGS "plRmyxetrnibs:N:aqvF:f:o:BhV" |
901 | #define PARSE_FLAGS "plRmyxetrnibs:N:TaqvF:f:o:BhV" |
790 | #define a_argument required_argument |
902 | #define a_argument required_argument |
791 | static struct option const long_opts[] = { |
903 | static struct option const long_opts[] = { |
792 | {"path", no_argument, NULL, 'p'}, |
904 | {"path", no_argument, NULL, 'p'}, |
793 | {"ldpath", no_argument, NULL, 'l'}, |
905 | {"ldpath", no_argument, NULL, 'l'}, |
794 | {"recursive", no_argument, NULL, 'R'}, |
906 | {"recursive", no_argument, NULL, 'R'}, |
… | |
… | |
799 | {"textrel", no_argument, NULL, 't'}, |
911 | {"textrel", no_argument, NULL, 't'}, |
800 | {"rpath", no_argument, NULL, 'r'}, |
912 | {"rpath", no_argument, NULL, 'r'}, |
801 | {"needed", no_argument, NULL, 'n'}, |
913 | {"needed", no_argument, NULL, 'n'}, |
802 | {"interp", no_argument, NULL, 'i'}, |
914 | {"interp", no_argument, NULL, 'i'}, |
803 | {"bind", no_argument, NULL, 'b'}, |
915 | {"bind", no_argument, NULL, 'b'}, |
804 | {"symbol", a_argument, NULL, 's'}, |
916 | {"symbol", a_argument, NULL, 's'}, |
805 | {"lib", a_argument, NULL, 'N'}, |
917 | {"lib", a_argument, NULL, 'N'}, |
|
|
918 | {"textrels", no_argument, NULL, 'T'}, |
806 | {"all", no_argument, NULL, 'a'}, |
919 | {"all", no_argument, NULL, 'a'}, |
807 | {"quiet", no_argument, NULL, 'q'}, |
920 | {"quiet", no_argument, NULL, 'q'}, |
808 | {"verbose", no_argument, NULL, 'v'}, |
921 | {"verbose", no_argument, NULL, 'v'}, |
809 | {"format", a_argument, NULL, 'F'}, |
922 | {"format", a_argument, NULL, 'F'}, |
810 | {"from", a_argument, NULL, 'f'}, |
923 | {"from", a_argument, NULL, 'f'}, |
811 | {"file", a_argument, NULL, 'o'}, |
924 | {"file", a_argument, NULL, 'o'}, |
812 | {"nobanner", no_argument, NULL, 'B'}, |
925 | {"nobanner", no_argument, NULL, 'B'}, |
813 | {"help", no_argument, NULL, 'h'}, |
926 | {"help", no_argument, NULL, 'h'}, |
814 | {"version", no_argument, NULL, 'V'}, |
927 | {"version", no_argument, NULL, 'V'}, |
815 | {NULL, no_argument, NULL, 0x0} |
928 | {NULL, no_argument, NULL, 0x0} |
816 | }; |
929 | }; |
… | |
… | |
828 | "Print NEEDED information", |
941 | "Print NEEDED information", |
829 | "Print INTERP information", |
942 | "Print INTERP information", |
830 | "Print BIND information", |
943 | "Print BIND information", |
831 | "Find a specified symbol", |
944 | "Find a specified symbol", |
832 | "Find a specified library", |
945 | "Find a specified library", |
|
|
946 | "Locate cause of TEXTREL", |
833 | "Print all scanned info (-x -e -t -r -n -i -b)\n", |
947 | "Print all scanned info (-x -e -t -r -n -i -b)\n", |
834 | "Only output 'bad' things", |
948 | "Only output 'bad' things", |
835 | "Be verbose (can be specified more than once)", |
949 | "Be verbose (can be specified more than once)", |
836 | "Use specified format for output", |
950 | "Use specified format for output", |
837 | "Read input stream from a filename", |
951 | "Read input stream from a filename", |
… | |
… | |
862 | |
976 | |
863 | puts("\nThe format modifiers for the -F option are:"); |
977 | puts("\nThe format modifiers for the -F option are:"); |
864 | puts(" F Filename \tx PaX Flags \te STACK/RELRO"); |
978 | puts(" F Filename \tx PaX Flags \te STACK/RELRO"); |
865 | puts(" t TEXTREL \tr RPATH \tn NEEDED"); |
979 | puts(" t TEXTREL \tr RPATH \tn NEEDED"); |
866 | puts(" i INTERP \tb BIND \ts symbol"); |
980 | puts(" i INTERP \tb BIND \ts symbol"); |
867 | puts(" N library \to Type"); |
981 | puts(" N library \to Type \tT TEXTRELs"); |
868 | puts(" p filename (with search path removed)"); |
982 | puts(" p filename (with search path removed)"); |
869 | puts(" f base filename"); |
983 | puts(" f base filename"); |
870 | puts("Prefix each modifier with '%' (verbose) or '#' (silent)"); |
984 | puts("Prefix each modifier with '%' (verbose) or '#' (silent)"); |
871 | |
985 | |
872 | exit(status); |
986 | exit(status); |
… | |
… | |
933 | case 't': show_textrel = 1; break; |
1047 | case 't': show_textrel = 1; break; |
934 | case 'r': show_rpath = 1; break; |
1048 | case 'r': show_rpath = 1; break; |
935 | case 'n': show_needed = 1; break; |
1049 | case 'n': show_needed = 1; break; |
936 | case 'i': show_interp = 1; break; |
1050 | case 'i': show_interp = 1; break; |
937 | case 'b': show_bind = 1; break; |
1051 | case 'b': show_bind = 1; break; |
|
|
1052 | case 'T': show_textrels = 1; break; |
938 | case 'q': be_quiet = 1; break; |
1053 | case 'q': be_quiet = 1; break; |
939 | case 'v': be_verbose = (be_verbose % 20) + 1; break; |
1054 | case 'v': be_verbose = (be_verbose % 20) + 1; break; |
940 | case 'a': show_pax = show_phdr = show_textrel = show_rpath = \ |
1055 | case 'a': show_pax = show_phdr = show_textrel = show_rpath = \ |
941 | show_needed = show_interp = show_bind = 1; break; |
1056 | show_needed = show_interp = show_bind = 1; break; |
942 | |
1057 | |
… | |
… | |
950 | } |
1065 | } |
951 | |
1066 | |
952 | /* let the format option override all other options */ |
1067 | /* let the format option override all other options */ |
953 | if (out_format) { |
1068 | if (out_format) { |
954 | show_pax = show_phdr = show_textrel = show_rpath = \ |
1069 | show_pax = show_phdr = show_textrel = show_rpath = \ |
955 | show_needed = show_interp = show_bind = 0; |
1070 | show_needed = show_interp = show_bind = show_textrels = 0; |
956 | for (i = 0; out_format[i]; ++i) { |
1071 | for (i = 0; out_format[i]; ++i) { |
957 | if (!IS_MODIFIER(out_format[i])) continue; |
1072 | if (!IS_MODIFIER(out_format[i])) continue; |
958 | |
1073 | |
959 | switch (out_format[++i]) { |
1074 | switch (out_format[++i]) { |
960 | case '%': break; |
1075 | case '%': break; |
… | |
… | |
970 | case 't': show_textrel = 1; break; |
1085 | case 't': show_textrel = 1; break; |
971 | case 'r': show_rpath = 1; break; |
1086 | case 'r': show_rpath = 1; break; |
972 | case 'n': show_needed = 1; break; |
1087 | case 'n': show_needed = 1; break; |
973 | case 'i': show_interp = 1; break; |
1088 | case 'i': show_interp = 1; break; |
974 | case 'b': show_bind = 1; break; |
1089 | case 'b': show_bind = 1; break; |
|
|
1090 | case 'T': show_textrels = 1; break; |
975 | default: |
1091 | default: |
976 | err("Invalid format specifier '%c' (byte %i)", |
1092 | err("Invalid format specifier '%c' (byte %i)", |
977 | out_format[i], i+1); |
1093 | out_format[i], i+1); |
978 | } |
1094 | } |
979 | } |
1095 | } |
980 | |
1096 | |
981 | /* construct our default format */ |
1097 | /* construct our default format */ |
982 | } else { |
1098 | } else { |
983 | size_t fmt_len = 30; |
1099 | size_t fmt_len = 30; |
984 | out_format = (char*)xmalloc(sizeof(char) * fmt_len); |
1100 | out_format = (char*)xmalloc(sizeof(char) * fmt_len); |
985 | if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); |
1101 | if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); |
986 | if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); |
1102 | if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); |
987 | if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); |
1103 | if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); |
988 | if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); |
1104 | if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); |
989 | if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); |
1105 | if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); |
990 | if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); |
1106 | if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); |
991 | if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); |
1107 | if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); |
992 | if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); |
1108 | if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); |
|
|
1109 | if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); |
993 | if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); |
1110 | if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); |
994 | if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); |
1111 | if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); |
995 | if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); |
1112 | if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); |
996 | } |
1113 | } |
997 | if (be_verbose > 2) printf("Format: %s\n", out_format); |
1114 | if (be_verbose > 2) printf("Format: %s\n", out_format); |
998 | |
1115 | |
999 | /* now lets actually do the scanning */ |
1116 | /* now lets actually do the scanning */ |
1000 | if (scan_ldpath || (show_rpath && be_quiet)) |
1117 | if (scan_ldpath || (show_rpath && be_quiet)) |