This patch provides the ability to identify the export-type of each exported symbols in Module.symvers. NOTE: It updates the Module.symvers file with the additional information as shown below. 0x0f8b92af platform_device_add_resources vmlinux EXPORT_SYMBOL_GPL 0xcf7efb2a ethtool_op_set_tx_csum vmlinux EXPORT_SYMBOL
Unified · Split
| @@ -22,6 +22,8 @@ int have_vmlinux = 0; · 21 unmodified lines | ||
| 22 | 22 | static int all_versions = 0; |
| 23 | 23 | /* If we are modposting external module set to 1 */ |
| 24 | 24 | static int external_module = 0; |
| 25 | +/* How a symbol is exported */ | |
| 26 | +enum export {export_plain, export_gpl, export_gpl_future, export_unknown}; | |
| 25 | 27 | |
| 26 | 28 | void fatal(const char *fmt, ...) |
| 27 | 29 | { |
| @@ -118,6 +120,7 @@ struct symbol { · 90 unmodified lines | ||
| 118 | 120 | unsigned int kernel:1; /* 1 if symbol is from kernel |
| 119 | 121 | * (only for external modules) **/ |
| 120 | 122 | unsigned int preloaded:1; /* 1 if symbol from Module.symvers */ |
| 123 | + enum export export; /* Type of export */ | |
| 121 | 124 | char name[0]; |
| 122 | 125 | }; |
| 123 | 126 | |
| @@ -153,7 +156,8 @@ static struct symbol *alloc_symbol(const char *name, unsigned int weak, · 29 unmodified lines | ||
| 153 | 156 | } |
| 154 | 157 | |
| 155 | 158 | /* For the hash of exported symbols */ |
| 156 | −static struct symbol *new_symbol(const char *name, struct module *module) | |
| 159 | +static struct symbol *new_symbol(const char *name, struct module *module, | |
| 160 | + enum export export) | |
| 157 | 161 | { |
| 158 | 162 | unsigned int hash; |
| 159 | 163 | struct symbol *new; |
| @@ -161,6 +165,7 @@ static struct symbol *new_symbol(const char *name, struct module *module) · 1 unmodified line | ||
| 161 | 165 | hash = tdb_hash(name) % SYMBOL_HASH_SIZE; |
| 162 | 166 | new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); |
| 163 | 167 | new->module = module; |
| 168 | + new->export = export; | |
| 164 | 169 | return new; |
| 165 | 170 | } |
| 166 | 171 | |
| @@ -179,16 +184,55 @@ static struct symbol *find_symbol(const char *name) · 12 unmodified lines | ||
| 179 | 184 | return NULL; |
| 180 | 185 | } |
| 181 | 186 | |
| 187 | +static struct { | |
| 188 | + const char *str; | |
| 189 | + enum export export; | |
| 190 | +} export_list[] = { | |
| 191 | + { .str = "EXPORT_SYMBOL", .export = export_plain }, | |
| 192 | + { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl }, | |
| 193 | + { .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future }, | |
| 194 | + { .str = "(unknown)", .export = export_unknown }, | |
| 195 | +}; | |
| 196 | + | |
| 197 | + | |
| 198 | +static const char *export_str(enum export ex) | |
| 199 | +{ | |
| 200 | + return export_list[ex].str; | |
| 201 | +} | |
| 202 | + | |
| 203 | +static enum export export_no(const char * s) | |
| 204 | +{ | |
| 205 | + int i; | |
| 206 | + for (i = 0; export_list[i].export != export_unknown; i++) { | |
| 207 | + if (strcmp(export_list[i].str, s) == 0) | |
| 208 | + return export_list[i].export; | |
| 209 | + } | |
| 210 | + return export_unknown; | |
| 211 | +} | |
| 212 | + | |
| 213 | +static enum export export_from_sec(struct elf_info *elf, Elf_Section sec) | |
| 214 | +{ | |
| 215 | + if (sec == elf->export_sec) | |
| 216 | + return export_plain; | |
| 217 | + else if (sec == elf->export_gpl_sec) | |
| 218 | + return export_gpl; | |
| 219 | + else if (sec == elf->export_gpl_future_sec) | |
| 220 | + return export_gpl_future; | |
| 221 | + else | |
| 222 | + return export_unknown; | |
| 223 | +} | |
| 224 | + | |
| 182 | 225 | /** |
| 183 | 226 | * Add an exported symbol - it may have already been added without a |
| 184 | 227 | * CRC, in this case just update the CRC |
| 185 | 228 | **/ |
| 186 | −static struct symbol *sym_add_exported(const char *name, struct module *mod) | |
| 229 | +static struct symbol *sym_add_exported(const char *name, struct module *mod, | |
| 230 | + enum export export) | |
| 187 | 231 | { |
| 188 | 232 | struct symbol *s = find_symbol(name); |
| 189 | 233 | |
| 190 | 234 | if (!s) { |
| 191 | − s = new_symbol(name, mod); | |
| 235 | + s = new_symbol(name, mod, export); | |
| 192 | 236 | } else { |
| 193 | 237 | if (!s->preloaded) { |
| 194 | 238 | warn("%s: '%s' exported twice. Previous export " |
| @@ -200,16 +244,17 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod) · 5 unmodified lines | ||
| 200 | 244 | s->preloaded = 0; |
| 201 | 245 | s->vmlinux = is_vmlinux(mod->name); |
| 202 | 246 | s->kernel = 0; |
| 247 | + s->export = export; | |
| 203 | 248 | return s; |
| 204 | 249 | } |
| 205 | 250 | |
| 206 | 251 | static void sym_update_crc(const char *name, struct module *mod, |
| 207 | − unsigned int crc) | |
| 252 | + unsigned int crc, enum export export) | |
| 208 | 253 | { |
| 209 | 254 | struct symbol *s = find_symbol(name); |
| 210 | 255 | |
| 211 | 256 | if (!s) |
| 212 | − s = new_symbol(name, mod); | |
| 257 | + s = new_symbol(name, mod, export); | |
| 213 | 258 | s->crc = crc; |
| 214 | 259 | s->crc_valid = 1; |
| 215 | 260 | } |
| @@ -309,13 +354,21 @@ static void parse_elf(struct elf_info *info, const char *filename) · 93 unmodified lines | ||
| 309 | 354 | for (i = 1; i < hdr->e_shnum; i++) { |
| 310 | 355 | const char *secstrings |
| 311 | 356 | = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
| 357 | + const char *secname; | |
| 312 | 358 | |
| 313 | 359 | if (sechdrs[i].sh_offset > info->size) |
| 314 | 360 | goto truncated; |
| 315 | − if (strcmp(secstrings+sechdrs[i].sh_name, ".modinfo") == 0) { | |
| 361 | + secname = secstrings + sechdrs[i].sh_name; | |
| 362 | + if (strcmp(secname, ".modinfo") == 0) { | |
| 316 | 363 | info->modinfo = (void *)hdr + sechdrs[i].sh_offset; |
| 317 | 364 | info->modinfo_len = sechdrs[i].sh_size; |
| 318 | − } | |
| 365 | + } else if (strcmp(secname, "__ksymtab") == 0) | |
| 366 | + info->export_sec = i; | |
| 367 | + else if (strcmp(secname, "__ksymtab_gpl") == 0) | |
| 368 | + info->export_gpl_sec = i; | |
| 369 | + else if (strcmp(secname, "__ksymtab_gpl_future") == 0) | |
| 370 | + info->export_gpl_future_sec = i; | |
| 371 | + | |
| 319 | 372 | if (sechdrs[i].sh_type != SHT_SYMTAB) |
| 320 | 373 | continue; |
| 321 | 374 | |
| @@ -353,6 +406,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, · 31 unmodified lines | ||
| 353 | 406 | Elf_Sym *sym, const char *symname) |
| 354 | 407 | { |
| 355 | 408 | unsigned int crc; |
| 409 | + enum export export = export_from_sec(info, sym->st_shndx); | |
| 356 | 410 | |
| 357 | 411 | switch (sym->st_shndx) { |
| 358 | 412 | case SHN_COMMON: |
| @@ -362,7 +416,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info, · 3 unmodified lines | ||
| 362 | 416 | /* CRC'd symbol */ |
| 363 | 417 | if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { |
| 364 | 418 | crc = (unsigned int) sym->st_value; |
| 365 | − sym_update_crc(symname + strlen(CRC_PFX), mod, crc); | |
| 419 | + sym_update_crc(symname + strlen(CRC_PFX), mod, crc, | |
| 420 | + export); | |
| 366 | 421 | } |
| 367 | 422 | break; |
| 368 | 423 | case SHN_UNDEF: |
| @@ -406,7 +461,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info, · 37 unmodified lines | ||
| 406 | 461 | default: |
| 407 | 462 | /* All exported symbols */ |
| 408 | 463 | if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { |
| 409 | − sym_add_exported(symname + strlen(KSYMTAB_PFX), mod); | |
| 464 | + sym_add_exported(symname + strlen(KSYMTAB_PFX), mod, | |
| 465 | + export); | |
| 410 | 466 | } |
| 411 | 467 | if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0) |
| 412 | 468 | mod->has_init = 1; |
| @@ -1146,6 +1202,9 @@ static void write_if_changed(struct buffer *b, const char *fname) · 733 unmodified lines | ||
| 1146 | 1202 | fclose(file); |
| 1147 | 1203 | } |
| 1148 | 1204 | |
| 1205 | +/* parse Module.symvers file. line format: | |
| 1206 | + * 0x12345678<tab>symbol<tab>module[<tab>export] | |
| 1207 | + **/ | |
| 1149 | 1208 | static void read_dump(const char *fname, unsigned int kernel) |
| 1150 | 1209 | { |
| 1151 | 1210 | unsigned long size, pos = 0; |
| @@ -1157,7 +1216,7 @@ static void read_dump(const char *fname, unsigned int kernel) · 5 unmodified lines | ||
| 1157 | 1216 | return; |
| 1158 | 1217 | |
| 1159 | 1218 | while ((line = get_next_line(&pos, file, size))) { |
| 1160 | − char *symname, *modname, *d; | |
| 1219 | + char *symname, *modname, *d, *export; | |
| 1161 | 1220 | unsigned int crc; |
| 1162 | 1221 | struct module *mod; |
| 1163 | 1222 | struct symbol *s; |
| @@ -1168,8 +1227,9 @@ static void read_dump(const char *fname, unsigned int kernel) · 4 unmodified lines | ||
| 1168 | 1227 | if (!(modname = strchr(symname, '\t'))) |
| 1169 | 1228 | goto fail; |
| 1170 | 1229 | *modname++ = '\0'; |
| 1171 | − if (strchr(modname, '\t')) | |
| 1172 | − goto fail; | |
| 1230 | + if (!(export = strchr(modname, '\t'))) | |
| 1231 | + *export++ = '\0'; | |
| 1232 | + | |
| 1173 | 1233 | crc = strtoul(line, &d, 16); |
| 1174 | 1234 | if (*symname == '\0' || *modname == '\0' || *d != '\0') |
| 1175 | 1235 | goto fail; |
| @@ -1181,10 +1241,10 @@ static void read_dump(const char *fname, unsigned int kernel) · 5 unmodified lines | ||
| 1181 | 1241 | mod = new_module(NOFAIL(strdup(modname))); |
| 1182 | 1242 | mod->skip = 1; |
| 1183 | 1243 | } |
| 1184 | − s = sym_add_exported(symname, mod); | |
| 1244 | + s = sym_add_exported(symname, mod, export_no(export)); | |
| 1185 | 1245 | s->kernel = kernel; |
| 1186 | 1246 | s->preloaded = 1; |
| 1187 | − sym_update_crc(symname, mod, crc); | |
| 1247 | + sym_update_crc(symname, mod, crc, export_no(export)); | |
| 1188 | 1248 | } |
| 1189 | 1249 | return; |
| 1190 | 1250 | fail: |
| @@ -1214,9 +1274,10 @@ static void write_dump(const char *fname) · 23 unmodified lines | ||
| 1214 | 1274 | symbol = symbolhash[n]; |
| 1215 | 1275 | while (symbol) { |
| 1216 | 1276 | if (dump_sym(symbol)) |
| 1217 | − buf_printf(&buf, "0x%08x\t%s\t%s\n", | |
| 1277 | + buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n", | |
| 1218 | 1278 | symbol->crc, symbol->name, |
| 1219 | − symbol->module->name); | |
| 1279 | + symbol->module->name, | |
| 1280 | + export_str(symbol->export)); | |
| 1220 | 1281 | symbol = symbol->next; |
| 1221 | 1282 | } |
| 1222 | 1283 | } |
| @@ -115,6 +115,9 @@ struct elf_info { · 114 unmodified lines | ||
| 115 | 115 | Elf_Shdr *sechdrs; |
| 116 | 116 | Elf_Sym *symtab_start; |
| 117 | 117 | Elf_Sym *symtab_stop; |
| 118 | + Elf_Section export_sec; | |
| 119 | + Elf_Section export_gpl_sec; | |
| 120 | + Elf_Section export_gpl_future_sec; | |
| 118 | 121 | const char *strtab; |
| 119 | 122 | char *modinfo; |
| 120 | 123 | unsigned int modinfo_len; |