diff options
| author | Andreas Gruenbacher <agruen@suse.de> | 2008-12-01 17:21:01 -0500 |
|---|---|---|
| committer | Sam Ravnborg <sam@ravnborg.org> | 2008-12-03 16:33:11 -0500 |
| commit | 64e6c1e12372840e7caf8e25325a9e9c5fd370e6 (patch) | |
| tree | aa47aa4e170dd4bb39c99cc7356231e2c61d64d2 | |
| parent | a680eedc6c621c75695c68198533fc3c98f4053b (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>
| -rw-r--r-- | scripts/Makefile.build | 16 | ||||
| -rw-r--r-- | scripts/genksyms/genksyms.c | 236 | ||||
| -rw-r--r-- | scripts/genksyms/genksyms.h | 6 |
3 files changed, 239 insertions, 19 deletions
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 468fbc9016c7..d21f0eac2e52 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build | |||
| @@ -153,12 +153,18 @@ $(obj)/%.i: $(src)/%.c FORCE | |||
| 153 | 153 | ||
| 154 | quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@ | 154 | quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@ |
| 155 | cmd_cc_symtypes_c = \ | 155 | cmd_cc_symtypes_c = \ |
| 156 | set -e; \ | ||
| 156 | $(CPP) -D__GENKSYMS__ $(c_flags) $< \ | 157 | $(CPP) -D__GENKSYMS__ $(c_flags) $< \ |
| 157 | | $(GENKSYMS) -T $@ >/dev/null; \ | 158 | | $(GENKSYMS) -T $@ \ |
| 159 | -r $(firstword $(wildcard \ | ||
| 160 | $(@:.symtypes=.symref) /dev/null)) \ | ||
| 161 | $(if $(KBUILD_PRESERVE),-p) \ | ||
| 162 | -a $(ARCH) \ | ||
| 163 | >/dev/null; \ | ||
| 158 | test -s $@ || rm -f $@ | 164 | test -s $@ || rm -f $@ |
| 159 | 165 | ||
| 160 | $(obj)/%.symtypes : $(src)/%.c FORCE | 166 | $(obj)/%.symtypes : $(src)/%.c FORCE |
| 161 | $(call if_changed_dep,cc_symtypes_c) | 167 | $(call cmd,cc_symtypes_c) |
| 162 | 168 | ||
| 163 | # C (.c) files | 169 | # C (.c) files |
| 164 | # The C file is compiled and updated dependency information is generated. | 170 | # The C file is compiled and updated dependency information is generated. |
| @@ -187,7 +193,11 @@ cmd_modversions = \ | |||
| 187 | if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ | 193 | if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ |
| 188 | $(CPP) -D__GENKSYMS__ $(c_flags) $< \ | 194 | $(CPP) -D__GENKSYMS__ $(c_flags) $< \ |
| 189 | | $(GENKSYMS) $(if $(KBUILD_SYMTYPES), \ | 195 | | $(GENKSYMS) $(if $(KBUILD_SYMTYPES), \ |
| 190 | -T $(@D)/$(@F:.o=.symtypes)) -a $(ARCH) \ | 196 | -T $(@:.o=.symtypes)) \ |
| 197 | -r $(firstword $(wildcard \ | ||
| 198 | $(@:.o=.symref) /dev/null)) \ | ||
| 199 | $(if $(KBUILD_PRESERVE),-p) \ | ||
| 200 | -a $(ARCH) \ | ||
| 191 | > $(@D)/.tmp_$(@F:.o=.ver); \ | 201 | > $(@D)/.tmp_$(@F:.o=.ver); \ |
| 192 | \ | 202 | \ |
| 193 | $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ | 203 | $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ |
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; | |||
| 42 | int cur_line = 1; | 42 | int cur_line = 1; |
| 43 | char *cur_filename; | 43 | char *cur_filename; |
| 44 | 44 | ||
| 45 | static int flag_debug, flag_dump_defs, flag_dump_types, flag_warnings; | 45 | static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types, |
| 46 | flag_preserve, flag_warnings; | ||
| 46 | static const char *arch = ""; | 47 | static const char *arch = ""; |
| 47 | static const char *mod_prefix = ""; | 48 | static const char *mod_prefix = ""; |
| 48 | 49 | ||
| @@ -58,6 +59,8 @@ static const char *const symbol_type_name[] = { | |||
| 58 | 59 | ||
| 59 | static int equal_list(struct string_list *a, struct string_list *b); | 60 | static int equal_list(struct string_list *a, struct string_list *b); |
| 60 | static void print_list(FILE * f, struct string_list *list); | 61 | static void print_list(FILE * f, struct string_list *list); |
| 62 | static void print_location(void); | ||
| 63 | static 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 | ||
| 160 | struct symbol *add_symbol(const char *name, enum symbol_type type, | 164 | static 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 | |||
| 179 | struct 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 | ||
| 246 | struct 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 | |||
| 252 | struct 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 | ||
| 201 | void free_node(struct string_list *node) | 260 | void 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 | |||
| 300 | struct 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 | |||
| 346 | static 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 | |||
| 239 | static void print_node(FILE * f, struct string_list *list) | 374 | static 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 | |||
| 596 | static void print_location(void) | ||
| 597 | { | ||
| 598 | fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line); | ||
| 599 | } | ||
| 600 | |||
| 601 | static 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 | |||
| 424 | void error_with_pos(const char *fmt, ...) | 609 | void 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 | ||
| 466 | int main(int argc, char **argv) | 654 | int 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 | ||
| 32 | enum symbol_status { | ||
| 33 | STATUS_UNCHANGED, STATUS_DEFINED, STATUS_MODIFIED | ||
| 34 | }; | ||
| 35 | |||
| 32 | struct string_list { | 36 | struct 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 | ||
| 48 | typedef struct string_list **yystype; | 54 | typedef struct string_list **yystype; |
