| 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/scanelf.c,v 1.95 2005/12/10 06:08:22 vapier Exp $ |
4 | * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.96 2005/12/28 22:26:47 solar Exp $ |
| 5 | * |
5 | * |
| 6 | * Copyright 2003-2005 Ned Ludd - <solar@gentoo.org> |
6 | * Copyright 2003-2005 Ned Ludd - <solar@gentoo.org> |
| 7 | * Copyright 2004-2005 Mike Frysinger - <vapier@gentoo.org> |
7 | * Copyright 2004-2005 Mike Frysinger - <vapier@gentoo.org> |
| 8 | */ |
8 | */ |
| 9 | |
9 | |
| … | |
… | |
| 14 | #include <limits.h> |
14 | #include <limits.h> |
| 15 | #include <string.h> |
15 | #include <string.h> |
| 16 | #include <errno.h> |
16 | #include <errno.h> |
| 17 | #include <unistd.h> |
17 | #include <unistd.h> |
| 18 | #include <sys/stat.h> |
18 | #include <sys/stat.h> |
|
|
19 | #include <sys/mman.h> |
|
|
20 | #include <fcntl.h> |
| 19 | #include <dirent.h> |
21 | #include <dirent.h> |
| 20 | #include <getopt.h> |
22 | #include <getopt.h> |
| 21 | #include <assert.h> |
23 | #include <assert.h> |
| 22 | #include "paxinc.h" |
24 | #include "paxinc.h" |
| 23 | |
25 | |
| 24 | static const char *rcsid = "$Id: scanelf.c,v 1.95 2005/12/10 06:08:22 vapier Exp $"; |
26 | static const char *rcsid = "$Id: scanelf.c,v 1.96 2005/12/28 22:26:47 solar Exp $"; |
| 25 | #define argv0 "scanelf" |
27 | #define argv0 "scanelf" |
| 26 | |
28 | |
| 27 | #define IS_MODIFIER(c) (c == '%' || c == '#') |
29 | #define IS_MODIFIER(c) (c == '%' || c == '#') |
| 28 | |
30 | |
| 29 | |
31 | |
| … | |
… | |
| 64 | static char *find_sym = NULL, *versioned_symname = NULL; |
66 | static char *find_sym = NULL, *versioned_symname = NULL; |
| 65 | static char *find_lib = NULL; |
67 | static char *find_lib = NULL; |
| 66 | static char *out_format = NULL; |
68 | static char *out_format = NULL; |
| 67 | static char *search_path = NULL; |
69 | static char *search_path = NULL; |
| 68 | static char gmatch = 0; |
70 | static char gmatch = 0; |
|
|
71 | static char printcache = 0; |
| 69 | |
72 | |
|
|
73 | |
|
|
74 | caddr_t ldcache = 0; |
|
|
75 | size_t ldcache_size = 0; |
| 70 | |
76 | |
| 71 | /* sub-funcs for scanelf_file() */ |
77 | /* sub-funcs for scanelf_file() */ |
| 72 | static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) |
78 | static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) |
| 73 | { |
79 | { |
| 74 | /* find the best SHT_DYNSYM and SHT_STRTAB sections */ |
80 | /* find the best SHT_DYNSYM and SHT_STRTAB sections */ |
| … | |
… | |
| 477 | } else if (rpath || runpath) |
483 | } else if (rpath || runpath) |
| 478 | xstrcat(ret, (runpath ? runpath : rpath), ret_len); |
484 | xstrcat(ret, (runpath ? runpath : rpath), ret_len); |
| 479 | else if (!be_quiet) |
485 | else if (!be_quiet) |
| 480 | xstrcat(ret, " - ", ret_len); |
486 | xstrcat(ret, " - ", ret_len); |
| 481 | } |
487 | } |
|
|
488 | |
|
|
489 | #define LDSO_CACHE_MAGIC "ld.so-" |
|
|
490 | #define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1) |
|
|
491 | #define LDSO_CACHE_VER "1.7.0" |
|
|
492 | #define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1) |
|
|
493 | |
|
|
494 | static char *lookup_cache_lib(char *); |
|
|
495 | static char *lookup_cache_lib(char *fname) |
|
|
496 | { |
|
|
497 | int fd = 0; |
|
|
498 | char *strs; |
|
|
499 | static char buf[_POSIX_PATH_MAX] = ""; |
|
|
500 | const char *cachefile = "/etc/ld.so.cache"; |
|
|
501 | struct stat st; |
|
|
502 | |
|
|
503 | typedef struct { |
|
|
504 | char magic[LDSO_CACHE_MAGIC_LEN]; |
|
|
505 | char version[LDSO_CACHE_VER_LEN]; |
|
|
506 | int nlibs; |
|
|
507 | } header_t; |
|
|
508 | |
|
|
509 | typedef struct { |
|
|
510 | int flags; |
|
|
511 | int sooffset; |
|
|
512 | int liboffset; |
|
|
513 | } libentry_t; |
|
|
514 | |
|
|
515 | header_t *header; |
|
|
516 | libentry_t *libent; |
|
|
517 | |
|
|
518 | if (fname == NULL) |
|
|
519 | return NULL; |
|
|
520 | |
|
|
521 | if (ldcache == 0) { |
|
|
522 | if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) < 0) |
|
|
523 | return NULL; |
|
|
524 | /* save the cache size for latter unmapping */ |
|
|
525 | ldcache_size = st.st_size; |
|
|
526 | |
|
|
527 | if ((ldcache = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == (caddr_t) -1) |
|
|
528 | return NULL; |
|
|
529 | |
|
|
530 | close(fd); |
|
|
531 | |
|
|
532 | if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)) |
|
|
533 | return NULL; |
|
|
534 | |
|
|
535 | if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN)) |
|
|
536 | return NULL; |
|
|
537 | } |
|
|
538 | |
|
|
539 | header = (header_t *) ldcache; |
|
|
540 | libent = (libentry_t *) (ldcache + sizeof(header_t)); |
|
|
541 | strs = (char *) &libent[header->nlibs]; |
|
|
542 | |
|
|
543 | for (fd = 0; fd < header->nlibs; fd++) { |
|
|
544 | if (strcmp(fname, strs + libent[fd].sooffset) != 0) |
|
|
545 | continue; |
|
|
546 | strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); |
|
|
547 | } |
|
|
548 | return buf; |
|
|
549 | } |
|
|
550 | |
|
|
551 | |
| 482 | static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) |
552 | static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) |
| 483 | { |
553 | { |
| 484 | unsigned long i; |
554 | unsigned long i; |
| 485 | char *needed; |
555 | char *needed; |
| 486 | void *strtbl_void; |
556 | void *strtbl_void; |
|
|
557 | char *p; |
| 487 | |
558 | |
| 488 | if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; |
559 | if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; |
| 489 | |
560 | |
| 490 | strtbl_void = elf_findsecbyname(elf, ".dynstr"); |
561 | strtbl_void = elf_findsecbyname(elf, ".dynstr"); |
| 491 | |
562 | |
| … | |
… | |
| 511 | } \ |
582 | } \ |
| 512 | needed = (char*)(elf->data + offset); \ |
583 | needed = (char*)(elf->data + offset); \ |
| 513 | if (op == 0) { \ |
584 | if (op == 0) { \ |
| 514 | if (!be_wewy_wewy_quiet) { \ |
585 | if (!be_wewy_wewy_quiet) { \ |
| 515 | if (*found_needed) xchrcat(ret, ',', ret_len); \ |
586 | if (*found_needed) xchrcat(ret, ',', ret_len); \ |
|
|
587 | if (printcache) \ |
|
|
588 | if ((p = lookup_cache_lib(needed)) != NULL) \ |
|
|
589 | needed = p; \ |
| 516 | xstrcat(ret, needed, ret_len); \ |
590 | xstrcat(ret, needed, ret_len); \ |
| 517 | } \ |
591 | } \ |
| 518 | *found_needed = 1; \ |
592 | *found_needed = 1; \ |
| 519 | } else { \ |
593 | } else { \ |
| 520 | if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ |
594 | if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ |
| … | |
… | |
| 1019 | |
1093 | |
| 1020 | free(path); |
1094 | free(path); |
| 1021 | } |
1095 | } |
| 1022 | |
1096 | |
| 1023 | |
1097 | |
| 1024 | |
|
|
| 1025 | /* usage / invocation handling functions */ |
1098 | /* usage / invocation handling functions */ |
| 1026 | #define PARSE_FLAGS "plRmyxetrnibSs:gN:TaqvF:f:o:BhV" |
1099 | #define PARSE_FLAGS "plRmyxetrnLibSs:gN:TaqvF:f:o:BhV" |
| 1027 | #define a_argument required_argument |
1100 | #define a_argument required_argument |
| 1028 | static struct option const long_opts[] = { |
1101 | static struct option const long_opts[] = { |
| 1029 | {"path", no_argument, NULL, 'p'}, |
1102 | {"path", no_argument, NULL, 'p'}, |
| 1030 | {"ldpath", no_argument, NULL, 'l'}, |
1103 | {"ldpath", no_argument, NULL, 'l'}, |
| 1031 | {"recursive", no_argument, NULL, 'R'}, |
1104 | {"recursive", no_argument, NULL, 'R'}, |
| … | |
… | |
| 1034 | {"pax", no_argument, NULL, 'x'}, |
1107 | {"pax", no_argument, NULL, 'x'}, |
| 1035 | {"header", no_argument, NULL, 'e'}, |
1108 | {"header", no_argument, NULL, 'e'}, |
| 1036 | {"textrel", no_argument, NULL, 't'}, |
1109 | {"textrel", no_argument, NULL, 't'}, |
| 1037 | {"rpath", no_argument, NULL, 'r'}, |
1110 | {"rpath", no_argument, NULL, 'r'}, |
| 1038 | {"needed", no_argument, NULL, 'n'}, |
1111 | {"needed", no_argument, NULL, 'n'}, |
|
|
1112 | {"ldcache", no_argument, NULL, 'L'}, |
| 1039 | {"interp", no_argument, NULL, 'i'}, |
1113 | {"interp", no_argument, NULL, 'i'}, |
| 1040 | {"bind", no_argument, NULL, 'b'}, |
1114 | {"bind", no_argument, NULL, 'b'}, |
| 1041 | {"soname", no_argument, NULL, 'S'}, |
1115 | {"soname", no_argument, NULL, 'S'}, |
| 1042 | {"symbol", a_argument, NULL, 's'}, |
1116 | {"symbol", a_argument, NULL, 's'}, |
| 1043 | {"lib", a_argument, NULL, 'N'}, |
1117 | {"lib", a_argument, NULL, 'N'}, |
| … | |
… | |
| 1064 | "Print PaX markings", |
1138 | "Print PaX markings", |
| 1065 | "Print GNU_STACK/PT_LOAD markings", |
1139 | "Print GNU_STACK/PT_LOAD markings", |
| 1066 | "Print TEXTREL information", |
1140 | "Print TEXTREL information", |
| 1067 | "Print RPATH information", |
1141 | "Print RPATH information", |
| 1068 | "Print NEEDED information", |
1142 | "Print NEEDED information", |
|
|
1143 | "Resolve NEEDED information (use with -n)", |
| 1069 | "Print INTERP information", |
1144 | "Print INTERP information", |
| 1070 | "Print BIND information", |
1145 | "Print BIND information", |
| 1071 | "Print SONAME information", |
1146 | "Print SONAME information", |
| 1072 | "Find a specified symbol", |
1147 | "Find a specified symbol", |
| 1073 | "Find a specified library", |
1148 | "Find a specified library", |
| … | |
… | |
| 1162 | if (out_format) warn("You prob don't want to specify -F twice"); |
1237 | if (out_format) warn("You prob don't want to specify -F twice"); |
| 1163 | out_format = optarg; |
1238 | out_format = optarg; |
| 1164 | break; |
1239 | break; |
| 1165 | } |
1240 | } |
| 1166 | |
1241 | |
| 1167 | case 'g': gmatch = 1; |
1242 | case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */ |
|
|
1243 | case 'L': printcache = 1; break; |
| 1168 | case 'y': scan_symlink = 0; break; |
1244 | case 'y': scan_symlink = 0; break; |
| 1169 | case 'B': show_banner = 0; break; |
1245 | case 'B': show_banner = 0; break; |
| 1170 | case 'l': scan_ldpath = 1; break; |
1246 | case 'l': scan_ldpath = 1; break; |
| 1171 | case 'p': scan_envpath = 1; break; |
1247 | case 'p': scan_envpath = 1; break; |
| 1172 | case 'R': dir_recurse = 1; break; |
1248 | case 'R': dir_recurse = 1; break; |
| … | |
… | |
| 1264 | |
1340 | |
| 1265 | /* clean up */ |
1341 | /* clean up */ |
| 1266 | if (versioned_symname) free(versioned_symname); |
1342 | if (versioned_symname) free(versioned_symname); |
| 1267 | for (i = 0; ldpaths[i]; ++i) |
1343 | for (i = 0; ldpaths[i]; ++i) |
| 1268 | free(ldpaths[i]); |
1344 | free(ldpaths[i]); |
|
|
1345 | |
|
|
1346 | if (ldcache != 0) |
|
|
1347 | munmap(ldcache, ldcache_size); |
| 1269 | } |
1348 | } |
| 1270 | |
1349 | |
| 1271 | |
1350 | |
| 1272 | |
1351 | |
| 1273 | /* utility funcs */ |
1352 | /* utility funcs */ |