/[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.214 Revision 1.215
1/* 1/*
2 * Copyright 2003-2007 Gentoo Foundation 2 * Copyright 2003-2007 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.214 2009/12/01 10:19:42 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.215 2009/12/03 08:01:45 vapier Exp $
5 * 5 *
6 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org> 6 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org> 7 * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org>
8 */ 8 */
9 9
10static const char *rcsid = "$Id: scanelf.c,v 1.214 2009/12/01 10:19:42 vapier Exp $"; 10static const char *rcsid = "$Id: scanelf.c,v 1.215 2009/12/03 08:01:45 vapier Exp $";
11const char * const argv0 = "scanelf"; 11const char * const argv0 = "scanelf";
12 12
13#include "paxinc.h" 13#include "paxinc.h"
14 14
15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+') 15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
25static void scanelf_envpath(void); 25static void scanelf_envpath(void);
26static void usage(int status); 26static void usage(int status);
27static char **get_split_env(const char *envvar); 27static char **get_split_env(const char *envvar);
28static void parseenv(void); 28static void parseenv(void);
29static int parseargs(int argc, char *argv[]); 29static int parseargs(int argc, char *argv[]);
30static int rematch(const char *regex, const char *match, int cflags);
31 30
32/* variables to control behavior */ 31/* variables to control behavior */
33static char match_etypes[126] = ""; 32static char match_etypes[126] = "";
34static char *ldpaths[256]; 33static char *ldpaths[256];
35static char scan_ldpath = 0; 34static char scan_ldpath = 0;
977 } 976 }
978 977
979 return NULL; 978 return NULL;
980} 979}
981 980
982static int scanelf_match_symname(const char *symname, const char *tomatch) 981/*
982 * We support the symbol form:
983 * [%[modifiers]%][[+-]<symbol name>][,[.....]]
984 * If the symbol name is empty, then all symbols are matched.
985 * If the symbol name is a glob ("*"), then all symbols are dumped (debug).
986 * Do not rely on this output format at all.
987 * Otherwise the symbol name is used to search (either regex or string compare).
988 * If the first char of the symbol name is a plus ("+"), then only match
989 * defined symbols. If it's a minus ("-"), only match undefined symbols.
990 * Putting modifiers in between the percent signs allows for more in depth
991 * filters. There are groups of modifiers. If you don't specify a member
992 * of a group, then all types in that group are matched. The current
993 * groups and their types are:
994 * STT group: STT_NOTYPE:n STT_OBJECT:o STT_FUNC:f SST_FILE:F
995 * STB group: STB_LOCAL:l STB_GLOBAL:g STB_WEAK:w
996 * SHN group: SHN_UNDEF:u SHN_ABS:a SHN_COMMON:c {defined}:d
997 * The "defined" value in the SHN group does not correspond to a SHN_xxx define.
998 * You can search for multiple symbols at once by seperating with a comma (",").
999 *
1000 * Some examples:
1001 * ELFs with a weak function "foo":
1002 * scanelf -s %wf%foo <ELFs>
1003 * ELFs that define the symbol "main":
1004 * scanelf -s +main <ELFs>
1005 * scanelf -s %d%main <ELFs>
1006 * ELFs that refer to the undefined symbol "brk":
1007 * scanelf -s -brk <ELFs>
1008 * scanelf -s %u%brk <ELFs>
1009 * All global defined objects in an ELF:
1010 * scanelf -s %ogd% <ELF>
1011 */
1012static void
1013scanelf_match_symname(elfobj *elf, char *found_sym, char **ret, size_t *ret_len, const char *symname,
1014 unsigned int stt, unsigned int stb, unsigned int shn, unsigned long size)
983{ 1015{
984 /* We do things differently when checking with regexp */ 1016 char *this_sym, *next_sym, saved = saved;
985 if (g_match) { 1017
986 return rematch(symname, tomatch, REG_EXTENDED) == 0; 1018 /* allow the user to specify a comma delimited list of symbols to search for */
1019 next_sym = NULL;
1020 do {
1021 bool inc_notype, inc_object, inc_func, inc_file,
1022 inc_local, inc_global, inc_weak,
1023 inc_def, inc_undef, inc_abs, inc_common;
1024
1025 if (next_sym) {
1026 next_sym[-1] = saved;
1027 this_sym = next_sym;
1028 } else
1029 this_sym = find_sym;
1030 if ((next_sym = strchr(this_sym, ','))) {
1031 /* make parsing easier by killing the comma temporarily */
1032 saved = *next_sym;
1033 *next_sym = '\0';
1034 next_sym += 1;
1035 }
1036
1037 /* symbol selection! */
1038 inc_notype = inc_object = inc_func = inc_file = \
1039 inc_local = inc_global = inc_weak = \
1040 inc_def = inc_undef = inc_abs = inc_common = \
1041 (*this_sym != '%');
1042
1043 /* parse the contents of %...% */
1044 if (!inc_notype) {
1045 while (*(this_sym++)) {
1046 if (*this_sym == '%') {
1047 ++this_sym;
1048 break;
1049 }
1050 switch (*this_sym) {
1051 case 'n': inc_notype = true; break;
1052 case 'o': inc_object = true; break;
1053 case 'f': inc_func = true; break;
1054 case 'F': inc_file = true; break;
1055 case 'l': inc_local = true; break;
1056 case 'g': inc_global = true; break;
1057 case 'w': inc_weak = true; break;
1058 case 'd': inc_def = true; break;
1059 case 'u': inc_undef = true; break;
1060 case 'a': inc_abs = true; break;
1061 case 'c': inc_common = true; break;
1062 default: err("invalid symbol selector '%c'", *this_sym);
1063 }
1064 }
1065
1066 /* If no types are matched, not match all */
1067 if (!inc_notype && !inc_object && !inc_func && !inc_file)
1068 inc_notype = inc_object = inc_func = inc_file = true;
1069 if (!inc_local && !inc_global && !inc_weak)
1070 inc_local = inc_global = inc_weak = true;
1071 if (!inc_def && !inc_undef && !inc_abs && !inc_common)
1072 inc_def = inc_undef = inc_abs = inc_common = true;
1073
1074 /* backwards compat for defined/undefined short hand */
1075 } else if (*this_sym == '+') {
1076 inc_undef = false;
1077 ++this_sym;
1078 } else if (*this_sym == '-') {
1079 inc_def = inc_abs = inc_common = false;
1080 ++this_sym;
1081 }
1082
1083 /* filter symbols */
1084 if ((!inc_notype && stt == STT_NOTYPE) || \
1085 (!inc_object && stt == STT_OBJECT) || \
1086 (!inc_func && stt == STT_FUNC ) || \
1087 (!inc_file && stt == STT_FILE ) || \
1088 (!inc_local && stb == STB_LOCAL ) || \
1089 (!inc_global && stb == STB_GLOBAL) || \
1090 (!inc_weak && stb == STB_WEAK ) || \
1091 (!inc_def && shn && shn < SHN_LORESERVE) || \
1092 (!inc_undef && shn == SHN_UNDEF ) || \
1093 (!inc_abs && shn == SHN_ABS ) || \
1094 (!inc_common && shn == SHN_COMMON))
1095 continue;
1096
1097 if (*this_sym == '*') {
1098 /* a "*" symbol gets you debug output */
1099 printf("%s(%s) %5lX %15s %15s %15s %s\n",
1100 ((*found_sym == 0) ? "\n\t" : "\t"),
1101 elf->base_filename,
1102 size,
1103 get_elfstttype(stt),
1104 get_elfstbtype(stb),
1105 get_elfshntype(shn),
1106 symname);
1107 goto matched;
1108
987 } else { 1109 } else {
1110 if (g_match) {
1111 /* regex match the symbol */
1112 if (rematch(this_sym, symname, REG_EXTENDED) != 0)
1113 continue;
1114
1115 } else if (*this_sym) {
1116 /* give empty symbols a "pass", else do a normal compare */
988 const size_t symname_len = strlen(symname); 1117 const size_t len = strlen(this_sym);
989 return (strncmp(symname, tomatch, symname_len) == 0 && 1118 if (!(strncmp(this_sym, symname, len) == 0 &&
990 /* Accept unversioned symbol names */ 1119 /* Accept unversioned symbol names */
991 (tomatch[symname_len] == '\0' || tomatch[symname_len] == '@')); 1120 (symname[len] == '\0' || symname[len] == '@')))
1121 continue;
1122 }
1123
1124 if (be_semi_verbose) {
1125 char buf[1024];
1126 snprintf(buf, sizeof(buf), "%lX %s %s",
1127 size,
1128 get_elfstttype(stt),
1129 this_sym);
1130 *ret = xstrdup(buf);
1131 } else {
1132 if (*ret) xchrcat(ret, ',', ret_len);
1133 xstrcat(ret, symname, ret_len);
1134 }
1135
1136 goto matched;
992 } 1137 }
1138 } while (next_sym);
1139
1140 return;
1141
1142 matched:
1143 *found_sym = 1;
1144 if (next_sym)
1145 next_sym[-1] = saved;
993} 1146}
994 1147
995static char *scanelf_file_sym(elfobj *elf, char *found_sym) 1148static char *scanelf_file_sym(elfobj *elf, char *found_sym)
996{ 1149{
997 unsigned long i; 1150 unsigned long i;
1018 if ((void*)sym > (void*)elf->data_end) { \ 1171 if ((void*)sym > (void*)elf->data_end) { \
1019 warnf("%s: corrupt ELF symbols - aborting", elf->filename); \ 1172 warnf("%s: corrupt ELF symbols - aborting", elf->filename); \
1020 goto break_out; \ 1173 goto break_out; \
1021 } \ 1174 } \
1022 if (sym->st_name) { \ 1175 if (sym->st_name) { \
1023 char *this_sym, *next_sym; \
1024 bool all_syms; \
1025 /* make sure the symbol name is in acceptable memory range */ \ 1176 /* make sure the symbol name is in acceptable memory range */ \
1026 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 1177 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
1027 if ((void*)symname > (void*)elf->data_end) { \ 1178 if ((void*)symname > (void*)elf->data_end) { \
1028 warnf("%s: corrupt ELF symbols", elf->filename); \ 1179 warnf("%s: corrupt ELF symbols", elf->filename); \
1029 ++sym; \ 1180 ++sym; \
1030 continue; \ 1181 continue; \
1031 } \ 1182 } \
1032 /* allow the user to specify a comma delimited list of symbols to search for */ \ 1183 scanelf_match_symname(elf, found_sym, \
1033 all_syms = false; \ 1184 &ret, &ret_len, symname, \
1034 next_sym = NULL; \ 1185 ELF##B##_ST_TYPE(EGET(sym->st_info)), \
1035 do { \ 1186 ELF##B##_ST_BIND(EGET(sym->st_info)), \
1036 bool inc_notype, inc_object, inc_func, inc_file, \ 1187 EGET(sym->st_shndx), \
1037 inc_local, inc_global, inc_weak, \ 1188 /* st_size can be 64bit, but no one is really that big, so screw em */ \
1038 inc_def, inc_undef, inc_abs, inc_common; \ 1189 EGET(sym->st_size)); \
1039 unsigned int stt, stb, shn; \
1040 char saved = saved; /* shut gcc up */ \
1041 if (next_sym) { \
1042 next_sym[-1] = saved; \
1043 this_sym = next_sym; \
1044 } else \
1045 this_sym = find_sym; \
1046 if ((next_sym = strchr(this_sym, ','))) { \
1047 saved = *next_sym; \
1048 *next_sym = '\0'; /* make parsing easier */ \
1049 next_sym += 1; /* Skip the comma */ \
1050 } \
1051 /* symbol selection! */ \
1052 inc_notype = inc_object = inc_func = inc_file = \
1053 inc_local = inc_global = inc_weak = \
1054 inc_def = inc_undef = inc_abs = inc_common = \
1055 (*this_sym != '%'); \
1056 if (!inc_notype) { \
1057 if (this_sym[1] == '%') \
1058 all_syms = true; /* %% hack */ \
1059 while (*(this_sym++)) { \
1060 if (*this_sym == '%') { \
1061 ++this_sym; \
1062 break; \
1063 } \
1064 switch (*this_sym) { \
1065 case 'n': inc_notype = true; break; \
1066 case 'o': inc_object = true; break; \
1067 case 'f': inc_func = true; break; \
1068 case 'F': inc_file = true; break; \
1069 case 'l': inc_local = true; break; \
1070 case 'g': inc_global = true; break; \
1071 case 'w': inc_weak = true; break; \
1072 case 'd': inc_def = true; break; \
1073 case 'u': inc_undef = true; break; \
1074 case 'a': inc_abs = true; break; \
1075 case 'c': inc_common = true; break; \
1076 default: err("invalid symbol selector '%c'", *this_sym); \
1077 } \
1078 } \
1079 if (!inc_notype && !inc_object && !inc_func && !inc_file) \
1080 inc_notype = inc_object = inc_func = inc_file = true; \
1081 if (!inc_local && !inc_global && !inc_weak) \
1082 inc_local = inc_global = inc_weak = true; \
1083 if (!inc_def && !inc_undef && !inc_abs && !inc_common) \
1084 inc_def = inc_undef = inc_abs = inc_common = true; \
1085 } else if (*this_sym == '+') { \
1086 inc_undef = false; \
1087 ++this_sym; \
1088 } else if (*this_sym == '-') { \
1089 inc_def = inc_abs = inc_common = false; \
1090 ++this_sym; \
1091 } \
1092 /* filter symbols */ \
1093 stt = ELF##B##_ST_TYPE(EGET(sym->st_info)); \
1094 stb = ELF##B##_ST_BIND(EGET(sym->st_info)); \
1095 shn = EGET(sym->st_shndx); \
1096 if ((!inc_notype && stt == STT_NOTYPE) || \
1097 (!inc_object && stt == STT_OBJECT) || \
1098 (!inc_func && stt == STT_FUNC ) || \
1099 (!inc_file && stt == STT_FILE ) || \
1100 (!inc_local && stb == STB_LOCAL ) || \
1101 (!inc_global && stb == STB_GLOBAL) || \
1102 (!inc_weak && stb == STB_WEAK ) || \
1103 (!inc_def && shn && shn < SHN_LORESERVE) || \
1104 (!inc_undef && shn == SHN_UNDEF ) || \
1105 (!inc_abs && shn == SHN_ABS ) || \
1106 (!inc_common && shn == SHN_COMMON)) \
1107 continue; \
1108 /* still here !? */ \
1109 if (*this_sym == '*' || !*this_sym) { \
1110 if (*this_sym == '*') \
1111 printf("%s(%s) %5lX %15s %15s %15s %s\n", \
1112 ((*found_sym == 0) ? "\n\t" : "\t"), \
1113 elf->base_filename, \
1114 (unsigned long)EGET(sym->st_size), \
1115 get_elfstttype(stt), \
1116 get_elfstbtype(stb), \
1117 get_elfshntype(shn), \
1118 symname); \
1119 else \
1120 printf("%s%s", ((*found_sym == 0) ? "" : ","), symname); \
1121 *found_sym = 1; \
1122 if (next_sym) next_sym[-1] = saved; \
1123 break; \
1124 } else if (scanelf_match_symname(this_sym, symname)) { \
1125 *found_sym = 1; \
1126 if (be_semi_verbose) { \
1127 char buf[1024]; \
1128 snprintf(buf, sizeof(buf), "%lX %s %s", \
1129 (unsigned long)EGET(sym->st_size), \
1130 get_elfstttype(stt), \
1131 this_sym); \
1132 ret = xstrdup(buf); \
1133 } else { \
1134 if (ret) xchrcat(&ret, ',', &ret_len); \
1135 xstrcat(&ret, symname, &ret_len); \
1136 } \
1137 if (next_sym) next_sym[-1] = saved; \
1138 if (all_syms) \
1139 break; \
1140 else \
1141 goto break_out; \
1142 } \
1143 } while (next_sym); \
1144 } \ 1190 } \
1145 ++sym; \ 1191 ++sym; \
1146 } } 1192 } }
1147 FIND_SYM(32) 1193 FIND_SYM(32)
1148 FIND_SYM(64) 1194 FIND_SYM(64)

Legend:
Removed from v.1.214  
changed lines
  Added in v.1.215

  ViewVC Help
Powered by ViewVC 1.1.20