aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/genksyms
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2008-12-01 17:21:01 -0500
committerSam Ravnborg <sam@ravnborg.org>2008-12-03 16:33:11 -0500
commit64e6c1e12372840e7caf8e25325a9e9c5fd370e6 (patch)
treeaa47aa4e170dd4bb39c99cc7356231e2c61d64d2 /scripts/genksyms
parenta680eedc6c621c75695c68198533fc3c98f4053b (diff)
genksyms: track symbol checksum changes
Sometimes it is preferable to avoid changes of exported symbol checksums (to avoid breaking externally provided modules). When a checksum change occurs, it can be hard to figure out what caused this change: underlying types may have changed, or additional type information may simply have become available at the point where a symbol is exported. Add a new --reference option to genksyms which allows it to report why checksums change, based on the type information dumps it creates with the --dump-types flag. Genksyms will read in such a dump from a previous run, and report which symbols have changed (and why). The behavior can be controlled for an entire build as follows: If KBUILD_SYMTYPES is set, genksyms uses --dump-types to produce *.symtypes dump files. If any *.symref files exist, those will be used as the reference to check against. If KBUILD_PRESERVE is set, checksum changes will fail the build. Signed-off-by: Andreas Gruenbacher <agruen@suse.de> Cc: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Diffstat (limited to 'scripts/genksyms')
-rw-r--r--scripts/genksyms/genksyms.c236
-rw-r--r--scripts/genksyms/genksyms.h6
2 files changed, 226 insertions, 16 deletions
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index c249274e005a..ddac1746908e 100644
--- a/scripts/genksyms/genksyms.c
+++ b/scripts/genksyms/genksyms.c
@@ -42,7 +42,8 @@ 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_dump_types, flag_warnings; 45static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
46 flag_preserve, flag_warnings;
46static const char *arch = ""; 47static const char *arch = "";
47static const char *mod_prefix = ""; 48static const char *mod_prefix = "";
48 49
@@ -58,6 +59,8 @@ static const char *const symbol_type_name[] = {
58 59
59static int equal_list(struct string_list *a, struct string_list *b); 60static int equal_list(struct string_list *a, struct string_list *b);
60static void print_list(FILE * f, struct string_list *list); 61static void print_list(FILE * f, struct string_list *list);
62static void print_location(void);
63static void print_type_name(enum symbol_type type, const char *name);
61 64
62/*----------------------------------------------------------------------*/ 65/*----------------------------------------------------------------------*/
63 66
@@ -151,27 +154,68 @@ struct symbol *find_symbol(const char *name, enum symbol_type ns)
151 154
152 for (sym = symtab[h]; sym; sym = sym->hash_next) 155 for (sym = symtab[h]; sym; sym = sym->hash_next)
153 if (map_to_ns(sym->type) == map_to_ns(ns) && 156 if (map_to_ns(sym->type) == map_to_ns(ns) &&
154 strcmp(name, sym->name) == 0) 157 strcmp(name, sym->name) == 0 &&
158 sym->is_declared)
155 break; 159 break;
156 160
157 return sym; 161 return sym;
158} 162}
159 163
160struct symbol *add_symbol(const char *name, enum symbol_type type, 164static int is_unknown_symbol(struct symbol *sym)
161 struct string_list *defn, int is_extern) 165{
166 struct string_list *defn;
167
168 return ((sym->type == SYM_STRUCT ||
169 sym->type == SYM_UNION ||
170 sym->type == SYM_ENUM) &&
171 (defn = sym->defn) && defn->tag == SYM_NORMAL &&
172 strcmp(defn->string, "}") == 0 &&
173 (defn = defn->next) && defn->tag == SYM_NORMAL &&
174 strcmp(defn->string, "UNKNOWN") == 0 &&
175 (defn = defn->next) && defn->tag == SYM_NORMAL &&
176 strcmp(defn->string, "{") == 0);
177}
178
179struct symbol *__add_symbol(const char *name, enum symbol_type type,
180 struct string_list *defn, int is_extern,
181 int is_reference)
162{ 182{
163 unsigned long h = crc32(name) % HASH_BUCKETS; 183 unsigned long h = crc32(name) % HASH_BUCKETS;
164 struct symbol *sym; 184 struct symbol *sym;
185 enum symbol_status status = STATUS_UNCHANGED;
165 186
166 for (sym = symtab[h]; sym; sym = sym->hash_next) { 187 for (sym = symtab[h]; sym; sym = sym->hash_next) {
167 if (map_to_ns(sym->type) == map_to_ns(type) 188 if (map_to_ns(sym->type) == map_to_ns(type) &&
168 && strcmp(name, sym->name) == 0) { 189 strcmp(name, sym->name) == 0) {
169 if (!equal_list(sym->defn, defn)) 190 if (is_reference)
191 /* fall through */ ;
192 else if (sym->type == type &&
193 equal_list(sym->defn, defn)) {
194 sym->is_declared = 1;
195 return sym;
196 } else if (!sym->is_declared) {
197 status = is_unknown_symbol(sym) ?
198 STATUS_DEFINED : STATUS_MODIFIED;
199 } else {
170 error_with_pos("redefinition of %s", name); 200 error_with_pos("redefinition of %s", name);
171 return sym; 201 return sym;
202 }
203 break;
172 } 204 }
173 } 205 }
174 206
207 if (sym) {
208 struct symbol **psym;
209
210 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
211 if (*psym == sym) {
212 *psym = sym->hash_next;
213 break;
214 }
215 }
216 --nsyms;
217 }
218
175 sym = xmalloc(sizeof(*sym)); 219 sym = xmalloc(sizeof(*sym));
176 sym->name = name; 220 sym->name = name;
177 sym->type = type; 221 sym->type = type;
@@ -183,6 +227,9 @@ struct symbol *add_symbol(const char *name, enum symbol_type type,
183 sym->hash_next = symtab[h]; 227 sym->hash_next = symtab[h];
184 symtab[h] = sym; 228 symtab[h] = sym;
185 229
230 sym->is_declared = !is_reference;
231 sym->status = status;
232
186 if (flag_debug) { 233 if (flag_debug) {
187 fprintf(debugfile, "Defn for %s %s == <", 234 fprintf(debugfile, "Defn for %s %s == <",
188 symbol_type_name[type], name); 235 symbol_type_name[type], name);
@@ -196,6 +243,18 @@ struct symbol *add_symbol(const char *name, enum symbol_type type,
196 return sym; 243 return sym;
197} 244}
198 245
246struct symbol *add_symbol(const char *name, enum symbol_type type,
247 struct string_list *defn, int is_extern)
248{
249 return __add_symbol(name, type, defn, is_extern, 0);
250}
251
252struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
253 struct string_list *defn, int is_extern)
254{
255 return __add_symbol(name, type, defn, is_extern, 1);
256}
257
199/*----------------------------------------------------------------------*/ 258/*----------------------------------------------------------------------*/
200 259
201void free_node(struct string_list *node) 260void free_node(struct string_list *node)
@@ -236,6 +295,82 @@ static int equal_list(struct string_list *a, struct string_list *b)
236 return !a && !b; 295 return !a && !b;
237} 296}
238 297
298#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
299
300struct string_list *read_node(FILE *f)
301{
302 char buffer[256];
303 struct string_list node = {
304 .string = buffer,
305 .tag = SYM_NORMAL };
306 int c;
307
308 while ((c = fgetc(f)) != EOF) {
309 if (c == ' ') {
310 if (node.string == buffer)
311 continue;
312 break;
313 } else if (c == '\n') {
314 if (node.string == buffer)
315 return NULL;
316 ungetc(c, f);
317 break;
318 }
319 if (node.string >= buffer + sizeof(buffer) - 1) {
320 fprintf(stderr, "Token too long\n");
321 exit(1);
322 }
323 *node.string++ = c;
324 }
325 if (node.string == buffer)
326 return NULL;
327 *node.string = 0;
328 node.string = buffer;
329
330 if (node.string[1] == '#') {
331 int n;
332
333 for (n = 0; n < ARRAY_SIZE(symbol_type_name); n++) {
334 if (node.string[0] == symbol_type_name[n][0]) {
335 node.tag = n;
336 node.string += 2;
337 return copy_node(&node);
338 }
339 }
340 fprintf(stderr, "Unknown type %c\n", node.string[0]);
341 exit(1);
342 }
343 return copy_node(&node);
344}
345
346static void read_reference(FILE *f)
347{
348 while (!feof(f)) {
349 struct string_list *defn = NULL;
350 struct string_list *sym, *def;
351 int is_extern = 0;
352
353 sym = read_node(f);
354 if (!sym)
355 continue;
356 def = read_node(f);
357 if (def && def->tag == SYM_NORMAL &&
358 !strcmp(def->string, "extern")) {
359 is_extern = 1;
360 free_node(def);
361 def = read_node(f);
362 }
363 while (def) {
364 def->next = defn;
365 defn = def;
366 def = read_node(f);
367 }
368 add_reference_symbol(xstrdup(sym->string), sym->tag,
369 defn, is_extern);
370 free_node(sym);
371 }
372}
373
239static void print_node(FILE * f, struct string_list *list) 374static void print_node(FILE * f, struct string_list *list)
240{ 375{
241 if (list->tag != SYM_NORMAL) { 376 if (list->tag != SYM_NORMAL) {
@@ -311,6 +446,7 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
311 446
312 case SYM_TYPEDEF: 447 case SYM_TYPEDEF:
313 subsym = find_symbol(cur->string, cur->tag); 448 subsym = find_symbol(cur->string, cur->tag);
449 /* FIXME: Bad reference files can segfault here. */
314 if (subsym->expansion_trail) { 450 if (subsym->expansion_trail) {
315 if (flag_dump_defs) 451 if (flag_dump_defs)
316 fprintf(debugfile, "%s ", cur->string); 452 fprintf(debugfile, "%s ", cur->string);
@@ -347,9 +483,22 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
347 t = n; 483 t = n;
348 484
349 n = xmalloc(sizeof(*n)); 485 n = xmalloc(sizeof(*n));
350 n->string = xstrdup("{ UNKNOWN }"); 486 n->string = xstrdup("{");
351 n->tag = SYM_NORMAL; 487 n->tag = SYM_NORMAL;
352 n->next = t; 488 n->next = t;
489 t = n;
490
491 n = xmalloc(sizeof(*n));
492 n->string = xstrdup("UNKNOWN");
493 n->tag = SYM_NORMAL;
494 n->next = t;
495 t = n;
496
497 n = xmalloc(sizeof(*n));
498 n->string = xstrdup("}");
499 n->tag = SYM_NORMAL;
500 n->next = t;
501 t = n;
353 502
354 subsym = 503 subsym =
355 add_symbol(cur->string, cur->tag, n, 0); 504 add_symbol(cur->string, cur->tag, n, 0);
@@ -397,20 +546,42 @@ void export_symbol(const char *name)
397 error_with_pos("export undefined symbol %s", name); 546 error_with_pos("export undefined symbol %s", name);
398 else { 547 else {
399 unsigned long crc; 548 unsigned long crc;
549 int has_changed = 0;
400 550
401 if (flag_dump_defs) 551 if (flag_dump_defs)
402 fprintf(debugfile, "Export %s == <", name); 552 fprintf(debugfile, "Export %s == <", name);
403 553
404 expansion_trail = (struct symbol *)-1L; 554 expansion_trail = (struct symbol *)-1L;
405 555
556 sym->expansion_trail = expansion_trail;
557 expansion_trail = sym;
406 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff; 558 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
407 559
408 sym = expansion_trail; 560 sym = expansion_trail;
409 while (sym != (struct symbol *)-1L) { 561 while (sym != (struct symbol *)-1L) {
410 struct symbol *n = sym->expansion_trail; 562 struct symbol *n = sym->expansion_trail;
563
564 if (sym->status != STATUS_UNCHANGED) {
565 if (!has_changed) {
566 print_location();
567 fprintf(stderr, "%s: %s: modversion "
568 "changed because of changes "
569 "in ", flag_preserve ? "error" :
570 "warning", name);
571 } else
572 fprintf(stderr, ", ");
573 print_type_name(sym->type, sym->name);
574 if (sym->status == STATUS_DEFINED)
575 fprintf(stderr, " (became defined)");
576 has_changed = 1;
577 if (flag_preserve)
578 errors++;
579 }
411 sym->expansion_trail = 0; 580 sym->expansion_trail = 0;
412 sym = n; 581 sym = n;
413 } 582 }
583 if (has_changed)
584 fprintf(stderr, "\n");
414 585
415 if (flag_dump_defs) 586 if (flag_dump_defs)
416 fputs(">\n", debugfile); 587 fputs(">\n", debugfile);
@@ -421,13 +592,26 @@ void export_symbol(const char *name)
421} 592}
422 593
423/*----------------------------------------------------------------------*/ 594/*----------------------------------------------------------------------*/
595
596static void print_location(void)
597{
598 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
599}
600
601static void print_type_name(enum symbol_type type, const char *name)
602{
603 if (type != SYM_NORMAL)
604 fprintf(stderr, "%s %s", symbol_type_name[type], name);
605 else
606 fprintf(stderr, "%s", name);
607}
608
424void error_with_pos(const char *fmt, ...) 609void error_with_pos(const char *fmt, ...)
425{ 610{
426 va_list args; 611 va_list args;
427 612
428 if (flag_warnings) { 613 if (flag_warnings) {
429 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", 614 print_location();
430 cur_line);
431 615
432 va_start(args, fmt); 616 va_start(args, fmt);
433 vfprintf(stderr, fmt, args); 617 vfprintf(stderr, fmt, args);
@@ -445,7 +629,9 @@ static void genksyms_usage(void)
445 " -a, --arch Select architecture\n" 629 " -a, --arch Select architecture\n"
446 " -d, --debug Increment the debug level (repeatable)\n" 630 " -d, --debug Increment the debug level (repeatable)\n"
447 " -D, --dump Dump expanded symbol defs (for debugging only)\n" 631 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
448 " -T, --dump-types file Dump expanded types into file (for debugging only)\n" 632 " -r, --reference file Read reference symbols from a file\n"
633 " -T, --dump-types file Dump expanded types into file\n"
634 " -p, --preserve Preserve reference modversions or fail\n"
449 " -w, --warnings Enable warnings\n" 635 " -w, --warnings Enable warnings\n"
450 " -q, --quiet Disable warnings (default)\n" 636 " -q, --quiet Disable warnings (default)\n"
451 " -h, --help Print this message\n" 637 " -h, --help Print this message\n"
@@ -454,7 +640,9 @@ static void genksyms_usage(void)
454 " -a Select architecture\n" 640 " -a Select architecture\n"
455 " -d Increment the debug level (repeatable)\n" 641 " -d Increment the debug level (repeatable)\n"
456 " -D Dump expanded symbol defs (for debugging only)\n" 642 " -D Dump expanded symbol defs (for debugging only)\n"
457 " -T file Dump expanded types into file (for debugging only)\n" 643 " -r file Read reference symbols from a file\n"
644 " -T file Dump expanded types into file\n"
645 " -p Preserve reference modversions or fail\n"
458 " -w Enable warnings\n" 646 " -w Enable warnings\n"
459 " -q Disable warnings (default)\n" 647 " -q Disable warnings (default)\n"
460 " -h Print this message\n" 648 " -h Print this message\n"
@@ -465,7 +653,7 @@ static void genksyms_usage(void)
465 653
466int main(int argc, char **argv) 654int main(int argc, char **argv)
467{ 655{
468 FILE *dumpfile = NULL; 656 FILE *dumpfile = NULL, *ref_file = NULL;
469 int o; 657 int o;
470 658
471#ifdef __GNU_LIBRARY__ 659#ifdef __GNU_LIBRARY__
@@ -475,16 +663,18 @@ int main(int argc, char **argv)
475 {"warnings", 0, 0, 'w'}, 663 {"warnings", 0, 0, 'w'},
476 {"quiet", 0, 0, 'q'}, 664 {"quiet", 0, 0, 'q'},
477 {"dump", 0, 0, 'D'}, 665 {"dump", 0, 0, 'D'},
666 {"reference", 1, 0, 'r'},
478 {"dump-types", 1, 0, 'T'}, 667 {"dump-types", 1, 0, 'T'},
668 {"preserve", 0, 0, 'p'},
479 {"version", 0, 0, 'V'}, 669 {"version", 0, 0, 'V'},
480 {"help", 0, 0, 'h'}, 670 {"help", 0, 0, 'h'},
481 {0, 0, 0, 0} 671 {0, 0, 0, 0}
482 }; 672 };
483 673
484 while ((o = getopt_long(argc, argv, "a:dwqVDT:h", 674 while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph",
485 &long_opts[0], NULL)) != EOF) 675 &long_opts[0], NULL)) != EOF)
486#else /* __GNU_LIBRARY__ */ 676#else /* __GNU_LIBRARY__ */
487 while ((o = getopt(argc, argv, "a:dwqVDT:h")) != EOF) 677 while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF)
488#endif /* __GNU_LIBRARY__ */ 678#endif /* __GNU_LIBRARY__ */
489 switch (o) { 679 switch (o) {
490 case 'a': 680 case 'a':
@@ -505,6 +695,14 @@ int main(int argc, char **argv)
505 case 'D': 695 case 'D':
506 flag_dump_defs = 1; 696 flag_dump_defs = 1;
507 break; 697 break;
698 case 'r':
699 flag_reference = 1;
700 ref_file = fopen(optarg, "r");
701 if (!ref_file) {
702 perror(optarg);
703 return 1;
704 }
705 break;
508 case 'T': 706 case 'T':
509 flag_dump_types = 1; 707 flag_dump_types = 1;
510 dumpfile = fopen(optarg, "w"); 708 dumpfile = fopen(optarg, "w");
@@ -513,6 +711,9 @@ int main(int argc, char **argv)
513 return 1; 711 return 1;
514 } 712 }
515 break; 713 break;
714 case 'p':
715 flag_preserve = 1;
716 break;
516 case 'h': 717 case 'h':
517 genksyms_usage(); 718 genksyms_usage();
518 return 0; 719 return 0;
@@ -533,6 +734,9 @@ int main(int argc, char **argv)
533 /* setlinebuf(debugfile); */ 734 /* setlinebuf(debugfile); */
534 } 735 }
535 736
737 if (flag_reference)
738 read_reference(ref_file);
739
536 yyparse(); 740 yyparse();
537 741
538 if (flag_dump_types && visited_symbols) { 742 if (flag_dump_types && visited_symbols) {
diff --git a/scripts/genksyms/genksyms.h b/scripts/genksyms/genksyms.h
index 2668287aa498..2831158426cd 100644
--- a/scripts/genksyms/genksyms.h
+++ b/scripts/genksyms/genksyms.h
@@ -29,6 +29,10 @@ enum symbol_type {
29 SYM_NORMAL, SYM_TYPEDEF, SYM_ENUM, SYM_STRUCT, SYM_UNION 29 SYM_NORMAL, SYM_TYPEDEF, SYM_ENUM, SYM_STRUCT, SYM_UNION
30}; 30};
31 31
32enum symbol_status {
33 STATUS_UNCHANGED, STATUS_DEFINED, STATUS_MODIFIED
34};
35
32struct string_list { 36struct string_list {
33 struct string_list *next; 37 struct string_list *next;
34 enum symbol_type tag; 38 enum symbol_type tag;
@@ -43,6 +47,8 @@ struct symbol {
43 struct symbol *expansion_trail; 47 struct symbol *expansion_trail;
44 struct symbol *visited; 48 struct symbol *visited;
45 int is_extern; 49 int is_extern;
50 int is_declared;
51 enum symbol_status status;
46}; 52};
47 53
48typedef struct string_list **yystype; 54typedef struct string_list **yystype;