aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2006-05-09 14:37:30 -0400
committerSam Ravnborg <sam@mars.ravnborg.org>2006-06-24 17:42:46 -0400
commit15fde6751886fd972a64ed65ba49db309919c504 (patch)
tree513c1eec2135f65ba0d980627346f7c07ad2b897
parent3041e47e8b08d51188b2cbdbd9c1e6f43314c8f1 (diff)
kbuild: support for %.symtypes files
Here is a patch that adds a new -T option to genksyms for generating dumps of the type definition that makes up the symbol version hashes. This allows to trace modversion changes back to what caused them. The dump format is the name of the type defined, followed by its definition (which is almost C): s#list_head struct list_head { s#list_head * next , * prev ; } The s#, u#, e#, and t# prefixes stand for struct, union, enum, and typedef. The exported symbols do not define types, and thus do not have an x# prefix: nfs4_acl_get_whotype int nfs4_acl_get_whotype ( char * , t#u32 ) The symbol type defintion of a single file can be generated with: make fs/jbd/journal.symtypes If KBUILD_SYMTYPES is defined, all the *.symtypes of all object files that export symbols are generated. The single *.symtypes files can be combined into a single file after a kernel build with a script like the following: for f in $(find -name '*.symtypes' | sort); do f=${f#./} echo "/* ${f%.symtypes}.o */" cat $f echo done \ | sed -e '\:UNKNOWN:d' \ -e 's:[,;] }:}:g' \ -e 's:\([[({]\) :\1:g' \ -e 's: \([])},;]\):\1:g' \ -e 's: $::' \ $f \ | awk ' /^.#/ { if (defined[$1] == $0) { print $1 next } defined[$1] = $0 } { print } ' When the kernel ABI changes, diffing individual *.symtype files, or the combined files, against each other will show which symbol changes caused the ABI changes. This can save a tremendous amount of time. Dump the types that make up modversions Signed-off-by: Andreas Gruenbacher <agruen@suse.de> Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
-rw-r--r--Makefile5
-rw-r--r--scripts/Makefile.build12
-rw-r--r--scripts/genksyms/genksyms.c77
-rw-r--r--scripts/genksyms/genksyms.h1
4 files changed, 67 insertions, 28 deletions
diff --git a/Makefile b/Makefile
index 1888fabe4032..e8906694dcc5 100644
--- a/Makefile
+++ b/Makefile
@@ -969,7 +969,8 @@ clean: archclean $(clean-dirs)
969 $(call cmd,rmfiles) 969 $(call cmd,rmfiles)
970 @find . $(RCS_FIND_IGNORE) \ 970 @find . $(RCS_FIND_IGNORE) \
971 \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ 971 \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
972 -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \ 972 -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
973 -o -name '*.symtypes' \) \
973 -type f -print | xargs rm -f 974 -type f -print | xargs rm -f
974 975
975# mrproper - Delete all generated files, including .config 976# mrproper - Delete all generated files, including .config
@@ -1311,6 +1312,8 @@ endif
1311 $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) 1312 $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
1312%.o: %.S prepare scripts FORCE 1313%.o: %.S prepare scripts FORCE
1313 $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) 1314 $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
1315%.symtypes: %.c prepare scripts FORCE
1316 $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
1314 1317
1315# Modules 1318# Modules
1316/ %/: prepare scripts FORCE 1319/ %/: prepare scripts FORCE
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index e8e7d27cfc9a..3cb445cc7432 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -140,6 +140,15 @@ cmd_cc_i_c = $(CPP) $(c_flags) -o $@ $<
140%.i: %.c FORCE 140%.i: %.c FORCE
141 $(call if_changed_dep,cc_i_c) 141 $(call if_changed_dep,cc_i_c)
142 142
143quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
144cmd_cc_symtypes_c = \
145 $(CPP) -D__GENKSYMS__ $(c_flags) $< \
146 | $(GENKSYMS) -T $@ >/dev/null; \
147 test -s $@ || rm -f $@
148
149%.symtypes : %.c FORCE
150 $(call if_changed_dep,cc_symtypes_c)
151
143# C (.c) files 152# C (.c) files
144# The C file is compiled and updated dependency information is generated. 153# The C file is compiled and updated dependency information is generated.
145# (See cmd_cc_o_c + relevant part of rule_cc_o_c) 154# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
@@ -166,7 +175,8 @@ cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
166cmd_modversions = \ 175cmd_modversions = \
167 if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ 176 if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \
168 $(CPP) -D__GENKSYMS__ $(c_flags) $< \ 177 $(CPP) -D__GENKSYMS__ $(c_flags) $< \
169 | $(GENKSYMS) -a $(ARCH) \ 178 | $(GENKSYMS) $(if $(KBUILD_SYMTYPES), \
179 -T $(@D)/$(@F:.o=.symtypes)) -a $(ARCH) \
170 > $(@D)/.tmp_$(@F:.o=.ver); \ 180 > $(@D)/.tmp_$(@F:.o=.ver); \
171 \ 181 \
172 $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ 182 $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index 5b0344e20d61..b0381823e404 100644
--- a/scripts/genksyms/genksyms.c
+++ b/scripts/genksyms/genksyms.c
@@ -42,7 +42,7 @@ static FILE *debugfile;
42int cur_line = 1; 42int cur_line = 1;
43char *cur_filename; 43char *cur_filename;
44 44
45static int flag_debug, flag_dump_defs, flag_warnings; 45static int flag_debug, flag_dump_defs, flag_dump_types, flag_warnings;
46static const char *arch = ""; 46static const char *arch = "";
47static const char *mod_prefix = ""; 47static const char *mod_prefix = "";
48 48
@@ -50,6 +50,7 @@ static int errors;
50static int nsyms; 50static int nsyms;
51 51
52static struct symbol *expansion_trail; 52static struct symbol *expansion_trail;
53static struct symbol *visited_symbols;
53 54
54static const char *const symbol_type_name[] = { 55static const char *const symbol_type_name[] = {
55 "normal", "typedef", "enum", "struct", "union" 56 "normal", "typedef", "enum", "struct", "union"
@@ -176,6 +177,7 @@ struct symbol *add_symbol(const char *name, enum symbol_type type,
176 sym->type = type; 177 sym->type = type;
177 sym->defn = defn; 178 sym->defn = defn;
178 sym->expansion_trail = NULL; 179 sym->expansion_trail = NULL;
180 sym->visited = NULL;
179 sym->is_extern = is_extern; 181 sym->is_extern = is_extern;
180 182
181 sym->hash_next = symtab[h]; 183 sym->hash_next = symtab[h];
@@ -236,26 +238,11 @@ static int equal_list(struct string_list *a, struct string_list *b)
236 238
237static void print_node(FILE * f, struct string_list *list) 239static void print_node(FILE * f, struct string_list *list)
238{ 240{
239 switch (list->tag) { 241 if (list->tag != SYM_NORMAL) {
240 case SYM_STRUCT: 242 putc(symbol_type_name[list->tag][0], f);
241 putc('s', f);
242 goto printit;
243 case SYM_UNION:
244 putc('u', f);
245 goto printit;
246 case SYM_ENUM:
247 putc('e', f);
248 goto printit;
249 case SYM_TYPEDEF:
250 putc('t', f);
251 goto printit;
252
253 printit:
254 putc('#', f); 243 putc('#', f);
255 case SYM_NORMAL:
256 fputs(list->string, f);
257 break;
258 } 244 }
245 fputs(list->string, f);
259} 246}
260 247
261static void print_list(FILE * f, struct string_list *list) 248static void print_list(FILE * f, struct string_list *list)
@@ -287,9 +274,9 @@ static void print_list(FILE * f, struct string_list *list)
287 } 274 }
288} 275}
289 276
290static unsigned long expand_and_crc_list(struct string_list *list, 277static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
291 unsigned long crc)
292{ 278{
279 struct string_list *list = sym->defn;
293 struct string_list **e, **b; 280 struct string_list **e, **b;
294 struct string_list *tmp, **tmp2; 281 struct string_list *tmp, **tmp2;
295 int elem = 1; 282 int elem = 1;
@@ -332,7 +319,7 @@ static unsigned long expand_and_crc_list(struct string_list *list,
332 } else { 319 } else {
333 subsym->expansion_trail = expansion_trail; 320 subsym->expansion_trail = expansion_trail;
334 expansion_trail = subsym; 321 expansion_trail = subsym;
335 crc = expand_and_crc_list(subsym->defn, crc); 322 crc = expand_and_crc_sym(subsym, crc);
336 } 323 }
337 break; 324 break;
338 325
@@ -382,12 +369,22 @@ static unsigned long expand_and_crc_list(struct string_list *list,
382 } else { 369 } else {
383 subsym->expansion_trail = expansion_trail; 370 subsym->expansion_trail = expansion_trail;
384 expansion_trail = subsym; 371 expansion_trail = subsym;
385 crc = expand_and_crc_list(subsym->defn, crc); 372 crc = expand_and_crc_sym(subsym, crc);
386 } 373 }
387 break; 374 break;
388 } 375 }
389 } 376 }
390 377
378 {
379 static struct symbol **end = &visited_symbols;
380
381 if (!sym->visited) {
382 *end = sym;
383 end = &sym->visited;
384 sym->visited = (struct symbol *)-1L;
385 }
386 }
387
391 return crc; 388 return crc;
392} 389}
393 390
@@ -406,7 +403,7 @@ void export_symbol(const char *name)
406 403
407 expansion_trail = (struct symbol *)-1L; 404 expansion_trail = (struct symbol *)-1L;
408 405
409 crc = expand_and_crc_list(sym->defn, 0xffffffff) ^ 0xffffffff; 406 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
410 407
411 sym = expansion_trail; 408 sym = expansion_trail;
412 while (sym != (struct symbol *)-1L) { 409 while (sym != (struct symbol *)-1L) {
@@ -464,6 +461,7 @@ static void genksyms_usage(void)
464 461
465int main(int argc, char **argv) 462int main(int argc, char **argv)
466{ 463{
464 FILE *dumpfile = NULL;
467 int o; 465 int o;
468 466
469#ifdef __GNU_LIBRARY__ 467#ifdef __GNU_LIBRARY__
@@ -473,15 +471,16 @@ int main(int argc, char **argv)
473 {"warnings", 0, 0, 'w'}, 471 {"warnings", 0, 0, 'w'},
474 {"quiet", 0, 0, 'q'}, 472 {"quiet", 0, 0, 'q'},
475 {"dump", 0, 0, 'D'}, 473 {"dump", 0, 0, 'D'},
474 {"dump-types", 1, 0, 'T'},
476 {"version", 0, 0, 'V'}, 475 {"version", 0, 0, 'V'},
477 {"help", 0, 0, 'h'}, 476 {"help", 0, 0, 'h'},
478 {0, 0, 0, 0} 477 {0, 0, 0, 0}
479 }; 478 };
480 479
481 while ((o = getopt_long(argc, argv, "a:dwqVDk:p:", 480 while ((o = getopt_long(argc, argv, "a:dwqVDT:k:p:",
482 &long_opts[0], NULL)) != EOF) 481 &long_opts[0], NULL)) != EOF)
483#else /* __GNU_LIBRARY__ */ 482#else /* __GNU_LIBRARY__ */
484 while ((o = getopt(argc, argv, "a:dwqVDk:p:")) != EOF) 483 while ((o = getopt(argc, argv, "a:dwqVDT:k:p:")) != EOF)
485#endif /* __GNU_LIBRARY__ */ 484#endif /* __GNU_LIBRARY__ */
486 switch (o) { 485 switch (o) {
487 case 'a': 486 case 'a':
@@ -502,6 +501,14 @@ int main(int argc, char **argv)
502 case 'D': 501 case 'D':
503 flag_dump_defs = 1; 502 flag_dump_defs = 1;
504 break; 503 break;
504 case 'T':
505 flag_dump_types = 1;
506 dumpfile = fopen(optarg, "w");
507 if (!dumpfile) {
508 perror(optarg);
509 return 1;
510 }
511 break;
505 case 'h': 512 case 'h':
506 genksyms_usage(); 513 genksyms_usage();
507 return 0; 514 return 0;
@@ -524,6 +531,24 @@ int main(int argc, char **argv)
524 531
525 yyparse(); 532 yyparse();
526 533
534 if (flag_dump_types && visited_symbols) {
535 while (visited_symbols != (struct symbol *)-1L) {
536 struct symbol *sym = visited_symbols;
537
538 if (sym->type != SYM_NORMAL) {
539 putc(symbol_type_name[sym->type][0], dumpfile);
540 putc('#', dumpfile);
541 }
542 fputs(sym->name, dumpfile);
543 putc(' ', dumpfile);
544 print_list(dumpfile, sym->defn);
545 putc('\n', dumpfile);
546
547 visited_symbols = sym->visited;
548 sym->visited = NULL;
549 }
550 }
551
527 if (flag_debug) { 552 if (flag_debug) {
528 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n", 553 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
529 nsyms, HASH_BUCKETS, 554 nsyms, HASH_BUCKETS,
diff --git a/scripts/genksyms/genksyms.h b/scripts/genksyms/genksyms.h
index ab6f34f38735..2668287aa498 100644
--- a/scripts/genksyms/genksyms.h
+++ b/scripts/genksyms/genksyms.h
@@ -41,6 +41,7 @@ struct symbol {
41 enum symbol_type type; 41 enum symbol_type type;
42 struct string_list *defn; 42 struct string_list *defn;
43 struct symbol *expansion_trail; 43 struct symbol *expansion_trail;
44 struct symbol *visited;
44 int is_extern; 45 int is_extern;
45}; 46};
46 47