diff options
Diffstat (limited to 'scripts/mod/modpost.c')
-rw-r--r-- | scripts/mod/modpost.c | 93 |
1 files changed, 77 insertions, 16 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index a70f5ddb705c..ba2e4fc2af20 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
@@ -22,6 +22,8 @@ int have_vmlinux = 0; | |||
22 | static int all_versions = 0; | 22 | static int all_versions = 0; |
23 | /* If we are modposting external module set to 1 */ | 23 | /* If we are modposting external module set to 1 */ |
24 | static int external_module = 0; | 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 | void fatal(const char *fmt, ...) | 28 | void fatal(const char *fmt, ...) |
27 | { | 29 | { |
@@ -118,6 +120,7 @@ struct symbol { | |||
118 | unsigned int kernel:1; /* 1 if symbol is from kernel | 120 | unsigned int kernel:1; /* 1 if symbol is from kernel |
119 | * (only for external modules) **/ | 121 | * (only for external modules) **/ |
120 | unsigned int preloaded:1; /* 1 if symbol from Module.symvers */ | 122 | unsigned int preloaded:1; /* 1 if symbol from Module.symvers */ |
123 | enum export export; /* Type of export */ | ||
121 | char name[0]; | 124 | char name[0]; |
122 | }; | 125 | }; |
123 | 126 | ||
@@ -153,7 +156,8 @@ static struct symbol *alloc_symbol(const char *name, unsigned int weak, | |||
153 | } | 156 | } |
154 | 157 | ||
155 | /* For the hash of exported symbols */ | 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 | unsigned int hash; | 162 | unsigned int hash; |
159 | struct symbol *new; | 163 | struct symbol *new; |
@@ -161,6 +165,7 @@ static struct symbol *new_symbol(const char *name, struct module *module) | |||
161 | hash = tdb_hash(name) % SYMBOL_HASH_SIZE; | 165 | hash = tdb_hash(name) % SYMBOL_HASH_SIZE; |
162 | new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); | 166 | new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); |
163 | new->module = module; | 167 | new->module = module; |
168 | new->export = export; | ||
164 | return new; | 169 | return new; |
165 | } | 170 | } |
166 | 171 | ||
@@ -179,16 +184,55 @@ static struct symbol *find_symbol(const char *name) | |||
179 | return NULL; | 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 | * Add an exported symbol - it may have already been added without a | 226 | * Add an exported symbol - it may have already been added without a |
184 | * CRC, in this case just update the CRC | 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 | struct symbol *s = find_symbol(name); | 232 | struct symbol *s = find_symbol(name); |
189 | 233 | ||
190 | if (!s) { | 234 | if (!s) { |
191 | s = new_symbol(name, mod); | 235 | s = new_symbol(name, mod, export); |
192 | } else { | 236 | } else { |
193 | if (!s->preloaded) { | 237 | if (!s->preloaded) { |
194 | warn("%s: '%s' exported twice. Previous export " | 238 | warn("%s: '%s' exported twice. Previous export " |
@@ -200,16 +244,17 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod) | |||
200 | s->preloaded = 0; | 244 | s->preloaded = 0; |
201 | s->vmlinux = is_vmlinux(mod->name); | 245 | s->vmlinux = is_vmlinux(mod->name); |
202 | s->kernel = 0; | 246 | s->kernel = 0; |
247 | s->export = export; | ||
203 | return s; | 248 | return s; |
204 | } | 249 | } |
205 | 250 | ||
206 | static void sym_update_crc(const char *name, struct module *mod, | 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 | struct symbol *s = find_symbol(name); | 254 | struct symbol *s = find_symbol(name); |
210 | 255 | ||
211 | if (!s) | 256 | if (!s) |
212 | s = new_symbol(name, mod); | 257 | s = new_symbol(name, mod, export); |
213 | s->crc = crc; | 258 | s->crc = crc; |
214 | s->crc_valid = 1; | 259 | s->crc_valid = 1; |
215 | } | 260 | } |
@@ -309,13 +354,21 @@ static void parse_elf(struct elf_info *info, const char *filename) | |||
309 | for (i = 1; i < hdr->e_shnum; i++) { | 354 | for (i = 1; i < hdr->e_shnum; i++) { |
310 | const char *secstrings | 355 | const char *secstrings |
311 | = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 356 | = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
357 | const char *secname; | ||
312 | 358 | ||
313 | if (sechdrs[i].sh_offset > info->size) | 359 | if (sechdrs[i].sh_offset > info->size) |
314 | goto truncated; | 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 | info->modinfo = (void *)hdr + sechdrs[i].sh_offset; | 363 | info->modinfo = (void *)hdr + sechdrs[i].sh_offset; |
317 | info->modinfo_len = sechdrs[i].sh_size; | 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 | if (sechdrs[i].sh_type != SHT_SYMTAB) | 372 | if (sechdrs[i].sh_type != SHT_SYMTAB) |
320 | continue; | 373 | continue; |
321 | 374 | ||
@@ -353,6 +406,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, | |||
353 | Elf_Sym *sym, const char *symname) | 406 | Elf_Sym *sym, const char *symname) |
354 | { | 407 | { |
355 | unsigned int crc; | 408 | unsigned int crc; |
409 | enum export export = export_from_sec(info, sym->st_shndx); | ||
356 | 410 | ||
357 | switch (sym->st_shndx) { | 411 | switch (sym->st_shndx) { |
358 | case SHN_COMMON: | 412 | case SHN_COMMON: |
@@ -362,7 +416,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info, | |||
362 | /* CRC'd symbol */ | 416 | /* CRC'd symbol */ |
363 | if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { | 417 | if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { |
364 | crc = (unsigned int) sym->st_value; | 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 | break; | 422 | break; |
368 | case SHN_UNDEF: | 423 | case SHN_UNDEF: |
@@ -406,7 +461,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info, | |||
406 | default: | 461 | default: |
407 | /* All exported symbols */ | 462 | /* All exported symbols */ |
408 | if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { | 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 | if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0) | 467 | if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0) |
412 | mod->has_init = 1; | 468 | mod->has_init = 1; |
@@ -1146,6 +1202,9 @@ static void write_if_changed(struct buffer *b, const char *fname) | |||
1146 | fclose(file); | 1202 | fclose(file); |
1147 | } | 1203 | } |
1148 | 1204 | ||
1205 | /* parse Module.symvers file. line format: | ||
1206 | * 0x12345678<tab>symbol<tab>module[<tab>export] | ||
1207 | **/ | ||
1149 | static void read_dump(const char *fname, unsigned int kernel) | 1208 | static void read_dump(const char *fname, unsigned int kernel) |
1150 | { | 1209 | { |
1151 | unsigned long size, pos = 0; | 1210 | unsigned long size, pos = 0; |
@@ -1157,7 +1216,7 @@ static void read_dump(const char *fname, unsigned int kernel) | |||
1157 | return; | 1216 | return; |
1158 | 1217 | ||
1159 | while ((line = get_next_line(&pos, file, size))) { | 1218 | while ((line = get_next_line(&pos, file, size))) { |
1160 | char *symname, *modname, *d; | 1219 | char *symname, *modname, *d, *export; |
1161 | unsigned int crc; | 1220 | unsigned int crc; |
1162 | struct module *mod; | 1221 | struct module *mod; |
1163 | struct symbol *s; | 1222 | struct symbol *s; |
@@ -1168,8 +1227,9 @@ static void read_dump(const char *fname, unsigned int kernel) | |||
1168 | if (!(modname = strchr(symname, '\t'))) | 1227 | if (!(modname = strchr(symname, '\t'))) |
1169 | goto fail; | 1228 | goto fail; |
1170 | *modname++ = '\0'; | 1229 | *modname++ = '\0'; |
1171 | if (strchr(modname, '\t')) | 1230 | if (!(export = strchr(modname, '\t'))) |
1172 | goto fail; | 1231 | *export++ = '\0'; |
1232 | |||
1173 | crc = strtoul(line, &d, 16); | 1233 | crc = strtoul(line, &d, 16); |
1174 | if (*symname == '\0' || *modname == '\0' || *d != '\0') | 1234 | if (*symname == '\0' || *modname == '\0' || *d != '\0') |
1175 | goto fail; | 1235 | goto fail; |
@@ -1181,10 +1241,10 @@ static void read_dump(const char *fname, unsigned int kernel) | |||
1181 | mod = new_module(NOFAIL(strdup(modname))); | 1241 | mod = new_module(NOFAIL(strdup(modname))); |
1182 | mod->skip = 1; | 1242 | mod->skip = 1; |
1183 | } | 1243 | } |
1184 | s = sym_add_exported(symname, mod); | 1244 | s = sym_add_exported(symname, mod, export_no(export)); |
1185 | s->kernel = kernel; | 1245 | s->kernel = kernel; |
1186 | s->preloaded = 1; | 1246 | s->preloaded = 1; |
1187 | sym_update_crc(symname, mod, crc); | 1247 | sym_update_crc(symname, mod, crc, export_no(export)); |
1188 | } | 1248 | } |
1189 | return; | 1249 | return; |
1190 | fail: | 1250 | fail: |
@@ -1214,9 +1274,10 @@ static void write_dump(const char *fname) | |||
1214 | symbol = symbolhash[n]; | 1274 | symbol = symbolhash[n]; |
1215 | while (symbol) { | 1275 | while (symbol) { |
1216 | if (dump_sym(symbol)) | 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 | symbol->crc, symbol->name, | 1278 | symbol->crc, symbol->name, |
1219 | symbol->module->name); | 1279 | symbol->module->name, |
1280 | export_str(symbol->export)); | ||
1220 | symbol = symbol->next; | 1281 | symbol = symbol->next; |
1221 | } | 1282 | } |
1222 | } | 1283 | } |