aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/genksyms/genksyms.c
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/genksyms/genksyms.c')
-rw-r--r--scripts/genksyms/genksyms.c277
1 files changed, 258 insertions, 19 deletions
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index c249274e005a..f8bb4cabd62d 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, flag_asm;
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,83 @@ 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 if (!sym->is_declared && sym->is_override) {
195 print_location();
196 print_type_name(type, name);
197 fprintf(stderr, " modversion is "
198 "unchanged\n");
199 }
200 sym->is_declared = 1;
201 return sym;
202 } else if (!sym->is_declared) {
203 if (sym->is_override && flag_preserve) {
204 print_location();
205 fprintf(stderr, "ignoring ");
206 print_type_name(type, name);
207 fprintf(stderr, " modversion change\n");
208 sym->is_declared = 1;
209 return sym;
210 } else {
211 status = is_unknown_symbol(sym) ?
212 STATUS_DEFINED : STATUS_MODIFIED;
213 }
214 } else {
170 error_with_pos("redefinition of %s", name); 215 error_with_pos("redefinition of %s", name);
171 return sym; 216 return sym;
217 }
218 break;
172 } 219 }
173 } 220 }
174 221
222 if (sym) {
223 struct symbol **psym;
224
225 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
226 if (*psym == sym) {
227 *psym = sym->hash_next;
228 break;
229 }
230 }
231 --nsyms;
232 }
233
175 sym = xmalloc(sizeof(*sym)); 234 sym = xmalloc(sizeof(*sym));
176 sym->name = name; 235 sym->name = name;
177 sym->type = type; 236 sym->type = type;
@@ -183,6 +242,10 @@ struct symbol *add_symbol(const char *name, enum symbol_type type,
183 sym->hash_next = symtab[h]; 242 sym->hash_next = symtab[h];
184 symtab[h] = sym; 243 symtab[h] = sym;
185 244
245 sym->is_declared = !is_reference;
246 sym->status = status;
247 sym->is_override = 0;
248
186 if (flag_debug) { 249 if (flag_debug) {
187 fprintf(debugfile, "Defn for %s %s == <", 250 fprintf(debugfile, "Defn for %s %s == <",
188 symbol_type_name[type], name); 251 symbol_type_name[type], name);
@@ -196,6 +259,18 @@ struct symbol *add_symbol(const char *name, enum symbol_type type,
196 return sym; 259 return sym;
197} 260}
198 261
262struct symbol *add_symbol(const char *name, enum symbol_type type,
263 struct string_list *defn, int is_extern)
264{
265 return __add_symbol(name, type, defn, is_extern, 0);
266}
267
268struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
269 struct string_list *defn, int is_extern)
270{
271 return __add_symbol(name, type, defn, is_extern, 1);
272}
273
199/*----------------------------------------------------------------------*/ 274/*----------------------------------------------------------------------*/
200 275
201void free_node(struct string_list *node) 276void free_node(struct string_list *node)
@@ -236,6 +311,90 @@ static int equal_list(struct string_list *a, struct string_list *b)
236 return !a && !b; 311 return !a && !b;
237} 312}
238 313
314#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
315
316struct string_list *read_node(FILE *f)
317{
318 char buffer[256];
319 struct string_list node = {
320 .string = buffer,
321 .tag = SYM_NORMAL };
322 int c;
323
324 while ((c = fgetc(f)) != EOF) {
325 if (c == ' ') {
326 if (node.string == buffer)
327 continue;
328 break;
329 } else if (c == '\n') {
330 if (node.string == buffer)
331 return NULL;
332 ungetc(c, f);
333 break;
334 }
335 if (node.string >= buffer + sizeof(buffer) - 1) {
336 fprintf(stderr, "Token too long\n");
337 exit(1);
338 }
339 *node.string++ = c;
340 }
341 if (node.string == buffer)
342 return NULL;
343 *node.string = 0;
344 node.string = buffer;
345
346 if (node.string[1] == '#') {
347 int n;
348
349 for (n = 0; n < ARRAY_SIZE(symbol_type_name); n++) {
350 if (node.string[0] == symbol_type_name[n][0]) {
351 node.tag = n;
352 node.string += 2;
353 return copy_node(&node);
354 }
355 }
356 fprintf(stderr, "Unknown type %c\n", node.string[0]);
357 exit(1);
358 }
359 return copy_node(&node);
360}
361
362static void read_reference(FILE *f)
363{
364 while (!feof(f)) {
365 struct string_list *defn = NULL;
366 struct string_list *sym, *def;
367 int is_extern = 0, is_override = 0;
368 struct symbol *subsym;
369
370 sym = read_node(f);
371 if (sym && sym->tag == SYM_NORMAL &&
372 !strcmp(sym->string, "override")) {
373 is_override = 1;
374 free_node(sym);
375 sym = read_node(f);
376 }
377 if (!sym)
378 continue;
379 def = read_node(f);
380 if (def && def->tag == SYM_NORMAL &&
381 !strcmp(def->string, "extern")) {
382 is_extern = 1;
383 free_node(def);
384 def = read_node(f);
385 }
386 while (def) {
387 def->next = defn;
388 defn = def;
389 def = read_node(f);
390 }
391 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
392 defn, is_extern);
393 subsym->is_override = is_override;
394 free_node(sym);
395 }
396}
397
239static void print_node(FILE * f, struct string_list *list) 398static void print_node(FILE * f, struct string_list *list)
240{ 399{
241 if (list->tag != SYM_NORMAL) { 400 if (list->tag != SYM_NORMAL) {
@@ -311,6 +470,7 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
311 470
312 case SYM_TYPEDEF: 471 case SYM_TYPEDEF:
313 subsym = find_symbol(cur->string, cur->tag); 472 subsym = find_symbol(cur->string, cur->tag);
473 /* FIXME: Bad reference files can segfault here. */
314 if (subsym->expansion_trail) { 474 if (subsym->expansion_trail) {
315 if (flag_dump_defs) 475 if (flag_dump_defs)
316 fprintf(debugfile, "%s ", cur->string); 476 fprintf(debugfile, "%s ", cur->string);
@@ -347,9 +507,22 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
347 t = n; 507 t = n;
348 508
349 n = xmalloc(sizeof(*n)); 509 n = xmalloc(sizeof(*n));
350 n->string = xstrdup("{ UNKNOWN }"); 510 n->string = xstrdup("{");
511 n->tag = SYM_NORMAL;
512 n->next = t;
513 t = n;
514
515 n = xmalloc(sizeof(*n));
516 n->string = xstrdup("UNKNOWN");
517 n->tag = SYM_NORMAL;
518 n->next = t;
519 t = n;
520
521 n = xmalloc(sizeof(*n));
522 n->string = xstrdup("}");
351 n->tag = SYM_NORMAL; 523 n->tag = SYM_NORMAL;
352 n->next = t; 524 n->next = t;
525 t = n;
353 526
354 subsym = 527 subsym =
355 add_symbol(cur->string, cur->tag, n, 0); 528 add_symbol(cur->string, cur->tag, n, 0);
@@ -397,37 +570,75 @@ void export_symbol(const char *name)
397 error_with_pos("export undefined symbol %s", name); 570 error_with_pos("export undefined symbol %s", name);
398 else { 571 else {
399 unsigned long crc; 572 unsigned long crc;
573 int has_changed = 0;
400 574
401 if (flag_dump_defs) 575 if (flag_dump_defs)
402 fprintf(debugfile, "Export %s == <", name); 576 fprintf(debugfile, "Export %s == <", name);
403 577
404 expansion_trail = (struct symbol *)-1L; 578 expansion_trail = (struct symbol *)-1L;
405 579
580 sym->expansion_trail = expansion_trail;
581 expansion_trail = sym;
406 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff; 582 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
407 583
408 sym = expansion_trail; 584 sym = expansion_trail;
409 while (sym != (struct symbol *)-1L) { 585 while (sym != (struct symbol *)-1L) {
410 struct symbol *n = sym->expansion_trail; 586 struct symbol *n = sym->expansion_trail;
587
588 if (sym->status != STATUS_UNCHANGED) {
589 if (!has_changed) {
590 print_location();
591 fprintf(stderr, "%s: %s: modversion "
592 "changed because of changes "
593 "in ", flag_preserve ? "error" :
594 "warning", name);
595 } else
596 fprintf(stderr, ", ");
597 print_type_name(sym->type, sym->name);
598 if (sym->status == STATUS_DEFINED)
599 fprintf(stderr, " (became defined)");
600 has_changed = 1;
601 if (flag_preserve)
602 errors++;
603 }
411 sym->expansion_trail = 0; 604 sym->expansion_trail = 0;
412 sym = n; 605 sym = n;
413 } 606 }
607 if (has_changed)
608 fprintf(stderr, "\n");
414 609
415 if (flag_dump_defs) 610 if (flag_dump_defs)
416 fputs(">\n", debugfile); 611 fputs(">\n", debugfile);
417 612
418 /* Used as a linker script. */ 613 /* Used as assembly source or a linker script. */
419 printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc); 614 printf(flag_asm
615 ? ".equiv %s__crc_%s, %#08lx\n"
616 : "%s__crc_%s = %#08lx ;\n",
617 mod_prefix, name, crc);
420 } 618 }
421} 619}
422 620
423/*----------------------------------------------------------------------*/ 621/*----------------------------------------------------------------------*/
622
623static void print_location(void)
624{
625 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
626}
627
628static void print_type_name(enum symbol_type type, const char *name)
629{
630 if (type != SYM_NORMAL)
631 fprintf(stderr, "%s %s", symbol_type_name[type], name);
632 else
633 fprintf(stderr, "%s", name);
634}
635
424void error_with_pos(const char *fmt, ...) 636void error_with_pos(const char *fmt, ...)
425{ 637{
426 va_list args; 638 va_list args;
427 639
428 if (flag_warnings) { 640 if (flag_warnings) {
429 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", 641 print_location();
430 cur_line);
431 642
432 va_start(args, fmt); 643 va_start(args, fmt);
433 vfprintf(stderr, fmt, args); 644 vfprintf(stderr, fmt, args);
@@ -440,21 +651,27 @@ void error_with_pos(const char *fmt, ...)
440 651
441static void genksyms_usage(void) 652static void genksyms_usage(void)
442{ 653{
443 fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n" 654 fputs("Usage:\n" "genksyms [-aAdDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
444#ifdef __GNU_LIBRARY__ 655#ifdef __GNU_LIBRARY__
445 " -a, --arch Select architecture\n" 656 " -a, --arch Select architecture\n"
657 " -A, --asm Generate assembly rather than linker script\n"
446 " -d, --debug Increment the debug level (repeatable)\n" 658 " -d, --debug Increment the debug level (repeatable)\n"
447 " -D, --dump Dump expanded symbol defs (for debugging only)\n" 659 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
448 " -T, --dump-types file Dump expanded types into file (for debugging only)\n" 660 " -r, --reference file Read reference symbols from a file\n"
661 " -T, --dump-types file Dump expanded types into file\n"
662 " -p, --preserve Preserve reference modversions or fail\n"
449 " -w, --warnings Enable warnings\n" 663 " -w, --warnings Enable warnings\n"
450 " -q, --quiet Disable warnings (default)\n" 664 " -q, --quiet Disable warnings (default)\n"
451 " -h, --help Print this message\n" 665 " -h, --help Print this message\n"
452 " -V, --version Print the release version\n" 666 " -V, --version Print the release version\n"
453#else /* __GNU_LIBRARY__ */ 667#else /* __GNU_LIBRARY__ */
454 " -a Select architecture\n" 668 " -a Select architecture\n"
669 " -A Generate assembly rather than linker script\n"
455 " -d Increment the debug level (repeatable)\n" 670 " -d Increment the debug level (repeatable)\n"
456 " -D Dump expanded symbol defs (for debugging only)\n" 671 " -D Dump expanded symbol defs (for debugging only)\n"
457 " -T file Dump expanded types into file (for debugging only)\n" 672 " -r file Read reference symbols from a file\n"
673 " -T file Dump expanded types into file\n"
674 " -p Preserve reference modversions or fail\n"
458 " -w Enable warnings\n" 675 " -w Enable warnings\n"
459 " -q Disable warnings (default)\n" 676 " -q Disable warnings (default)\n"
460 " -h Print this message\n" 677 " -h Print this message\n"
@@ -465,26 +682,29 @@ static void genksyms_usage(void)
465 682
466int main(int argc, char **argv) 683int main(int argc, char **argv)
467{ 684{
468 FILE *dumpfile = NULL; 685 FILE *dumpfile = NULL, *ref_file = NULL;
469 int o; 686 int o;
470 687
471#ifdef __GNU_LIBRARY__ 688#ifdef __GNU_LIBRARY__
472 struct option long_opts[] = { 689 struct option long_opts[] = {
473 {"arch", 1, 0, 'a'}, 690 {"arch", 1, 0, 'a'},
691 {"asm", 0, 0, 'A'},
474 {"debug", 0, 0, 'd'}, 692 {"debug", 0, 0, 'd'},
475 {"warnings", 0, 0, 'w'}, 693 {"warnings", 0, 0, 'w'},
476 {"quiet", 0, 0, 'q'}, 694 {"quiet", 0, 0, 'q'},
477 {"dump", 0, 0, 'D'}, 695 {"dump", 0, 0, 'D'},
696 {"reference", 1, 0, 'r'},
478 {"dump-types", 1, 0, 'T'}, 697 {"dump-types", 1, 0, 'T'},
698 {"preserve", 0, 0, 'p'},
479 {"version", 0, 0, 'V'}, 699 {"version", 0, 0, 'V'},
480 {"help", 0, 0, 'h'}, 700 {"help", 0, 0, 'h'},
481 {0, 0, 0, 0} 701 {0, 0, 0, 0}
482 }; 702 };
483 703
484 while ((o = getopt_long(argc, argv, "a:dwqVDT:h", 704 while ((o = getopt_long(argc, argv, "a:dwqVADr:T:ph",
485 &long_opts[0], NULL)) != EOF) 705 &long_opts[0], NULL)) != EOF)
486#else /* __GNU_LIBRARY__ */ 706#else /* __GNU_LIBRARY__ */
487 while ((o = getopt(argc, argv, "a:dwqVDT:h")) != EOF) 707 while ((o = getopt(argc, argv, "a:dwqVADr:T:ph")) != EOF)
488#endif /* __GNU_LIBRARY__ */ 708#endif /* __GNU_LIBRARY__ */
489 switch (o) { 709 switch (o) {
490 case 'a': 710 case 'a':
@@ -502,9 +722,20 @@ int main(int argc, char **argv)
502 case 'V': 722 case 'V':
503 fputs("genksyms version 2.5.60\n", stderr); 723 fputs("genksyms version 2.5.60\n", stderr);
504 break; 724 break;
725 case 'A':
726 flag_asm = 1;
727 break;
505 case 'D': 728 case 'D':
506 flag_dump_defs = 1; 729 flag_dump_defs = 1;
507 break; 730 break;
731 case 'r':
732 flag_reference = 1;
733 ref_file = fopen(optarg, "r");
734 if (!ref_file) {
735 perror(optarg);
736 return 1;
737 }
738 break;
508 case 'T': 739 case 'T':
509 flag_dump_types = 1; 740 flag_dump_types = 1;
510 dumpfile = fopen(optarg, "w"); 741 dumpfile = fopen(optarg, "w");
@@ -513,6 +744,9 @@ int main(int argc, char **argv)
513 return 1; 744 return 1;
514 } 745 }
515 break; 746 break;
747 case 'p':
748 flag_preserve = 1;
749 break;
516 case 'h': 750 case 'h':
517 genksyms_usage(); 751 genksyms_usage();
518 return 0; 752 return 0;
@@ -533,12 +767,17 @@ int main(int argc, char **argv)
533 /* setlinebuf(debugfile); */ 767 /* setlinebuf(debugfile); */
534 } 768 }
535 769
770 if (flag_reference)
771 read_reference(ref_file);
772
536 yyparse(); 773 yyparse();
537 774
538 if (flag_dump_types && visited_symbols) { 775 if (flag_dump_types && visited_symbols) {
539 while (visited_symbols != (struct symbol *)-1L) { 776 while (visited_symbols != (struct symbol *)-1L) {
540 struct symbol *sym = visited_symbols; 777 struct symbol *sym = visited_symbols;
541 778
779 if (sym->is_override)
780 fputs("override ", dumpfile);
542 if (sym->type != SYM_NORMAL) { 781 if (sym->type != SYM_NORMAL) {
543 putc(symbol_type_name[sym->type][0], dumpfile); 782 putc(symbol_type_name[sym->type][0], dumpfile);
544 putc('#', dumpfile); 783 putc('#', dumpfile);