]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.31/patches.suse/genksyms-reference.diff
Add a patch to fix Intel E100 wake-on-lan problems.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.suse / genksyms-reference.diff
CommitLineData
6a930a95
BS
1From: Andreas Gruenbacher <agruen@suse.de>
2Subject: genksyms: track symbol checksum changes
3
4Sometimes it is preferable to avoid changes of exported symbol checksums (to
5avoid breaking externally provided modules). When a checksum change occurs, it
6can be hard to figure out what caused this change: underlying types may have
7changed, or additional type information may simply have become available at the
8point where a symbol is exported.
9
10Add a new --reference option to genksyms which allows it to report why
11checksums change, based on the type information dumps it creates with
12the --dump-types flag. Genksyms will read in such a dump from a previous run,
13and report which symbols have changed (and why).
14
15The behavior can be controlled for an entire build as follows: If
16KBUILD_SYMTYPES is set, genksyms uses --dump-types to produce *.symtypes dump
17files. If any *.symref files exist, those will be used as the reference to
18check against. If KBUILD_PRESERVE is set, checksum changes will fail the
19build.
20
21Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
22
23---
24 scripts/Makefile.build | 16 ++
25 scripts/genksyms/genksyms.c | 236 +++++++++++++++++++++++++++++++++++++++++---
26 scripts/genksyms/genksyms.h | 6 +
27 3 files changed, 239 insertions(+), 19 deletions(-)
28
29--- a/scripts/Makefile.build
30+++ b/scripts/Makefile.build
31@@ -153,12 +153,18 @@ $(obj)/%.i: $(src)/%.c FORCE
32
33 quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
34 cmd_cc_symtypes_c = \
35+ set -e; \
36 $(CPP) -D__GENKSYMS__ $(c_flags) $< \
37- | $(GENKSYMS) -T $@ >/dev/null; \
38+ | $(GENKSYMS) -T $@ \
39+ -r $(firstword $(wildcard \
40+ $(@:.symtypes=.symref) /dev/null)) \
41+ $(if $(KBUILD_PRESERVE),-p) \
42+ -a $(ARCH) \
43+ >/dev/null; \
44 test -s $@ || rm -f $@
45
46 $(obj)/%.symtypes : $(src)/%.c FORCE
47- $(call if_changed_dep,cc_symtypes_c)
48+ $(call cmd,cc_symtypes_c)
49
50 # C (.c) files
51 # The C file is compiled and updated dependency information is generated.
52@@ -187,7 +193,11 @@ cmd_modversions = \
53 if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \
54 $(CPP) -D__GENKSYMS__ $(c_flags) $< \
55 | $(GENKSYMS) $(if $(KBUILD_SYMTYPES), \
56- -T $(@D)/$(@F:.o=.symtypes)) -a $(ARCH) \
57+ -T $(@:.o=.symtypes)) \
58+ -r $(firstword $(wildcard \
59+ $(@:.o=.symref) /dev/null)) \
60+ $(if $(KBUILD_PRESERVE),-p) \
61+ -a $(ARCH) \
62 > $(@D)/.tmp_$(@F:.o=.ver); \
63 \
64 $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \
65--- a/scripts/genksyms/genksyms.c
66+++ b/scripts/genksyms/genksyms.c
67@@ -42,7 +42,8 @@ static FILE *debugfile;
68 int cur_line = 1;
69 char *cur_filename;
70
71-static int flag_debug, flag_dump_defs, flag_dump_types, flag_warnings;
72+static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
73+ flag_preserve, flag_warnings;
74 static const char *arch = "";
75 static const char *mod_prefix = "";
76
77@@ -58,6 +59,8 @@ static const char *const symbol_type_nam
78
79 static int equal_list(struct string_list *a, struct string_list *b);
80 static void print_list(FILE * f, struct string_list *list);
81+static void print_location(void);
82+static void print_type_name(enum symbol_type type, const char *name);
83
84 /*----------------------------------------------------------------------*/
85
86@@ -151,25 +154,66 @@ struct symbol *find_symbol(const char *n
87
88 for (sym = symtab[h]; sym; sym = sym->hash_next)
89 if (map_to_ns(sym->type) == map_to_ns(ns) &&
90- strcmp(name, sym->name) == 0)
91+ strcmp(name, sym->name) == 0 &&
92+ sym->is_declared)
93 break;
94
95 return sym;
96 }
97
98-struct symbol *add_symbol(const char *name, enum symbol_type type,
99- struct string_list *defn, int is_extern)
100+static int is_unknown_symbol(struct symbol *sym)
101+{
102+ struct string_list *defn;
103+
104+ return ((sym->type == SYM_STRUCT ||
105+ sym->type == SYM_UNION ||
106+ sym->type == SYM_ENUM) &&
107+ (defn = sym->defn) && defn->tag == SYM_NORMAL &&
108+ strcmp(defn->string, "}") == 0 &&
109+ (defn = defn->next) && defn->tag == SYM_NORMAL &&
110+ strcmp(defn->string, "UNKNOWN") == 0 &&
111+ (defn = defn->next) && defn->tag == SYM_NORMAL &&
112+ strcmp(defn->string, "{") == 0);
113+}
114+
115+struct symbol *__add_symbol(const char *name, enum symbol_type type,
116+ struct string_list *defn, int is_extern,
117+ int is_reference)
118 {
119 unsigned long h = crc32(name) % HASH_BUCKETS;
120 struct symbol *sym;
121+ enum symbol_status status = STATUS_UNCHANGED;
122
123 for (sym = symtab[h]; sym; sym = sym->hash_next) {
124- if (map_to_ns(sym->type) == map_to_ns(type)
125- && strcmp(name, sym->name) == 0) {
126- if (!equal_list(sym->defn, defn))
127+ if (map_to_ns(sym->type) == map_to_ns(type) &&
128+ strcmp(name, sym->name) == 0) {
129+ if (is_reference)
130+ /* fall through */ ;
131+ else if (sym->type == type &&
132+ equal_list(sym->defn, defn)) {
133+ sym->is_declared = 1;
134+ return sym;
135+ } else if (!sym->is_declared) {
136+ status = is_unknown_symbol(sym) ?
137+ STATUS_DEFINED : STATUS_MODIFIED;
138+ } else {
139 error_with_pos("redefinition of %s", name);
140- return sym;
141+ return sym;
142+ }
143+ break;
144+ }
145+ }
146+
147+ if (sym) {
148+ struct symbol **psym;
149+
150+ for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
151+ if (*psym == sym) {
152+ *psym = sym->hash_next;
153+ break;
154+ }
155 }
156+ --nsyms;
157 }
158
159 sym = xmalloc(sizeof(*sym));
160@@ -183,6 +227,9 @@ struct symbol *add_symbol(const char *na
161 sym->hash_next = symtab[h];
162 symtab[h] = sym;
163
164+ sym->is_declared = !is_reference;
165+ sym->status = status;
166+
167 if (flag_debug) {
168 fprintf(debugfile, "Defn for %s %s == <",
169 symbol_type_name[type], name);
170@@ -196,6 +243,18 @@ struct symbol *add_symbol(const char *na
171 return sym;
172 }
173
174+struct symbol *add_symbol(const char *name, enum symbol_type type,
175+ struct string_list *defn, int is_extern)
176+{
177+ return __add_symbol(name, type, defn, is_extern, 0);
178+}
179+
180+struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
181+ struct string_list *defn, int is_extern)
182+{
183+ return __add_symbol(name, type, defn, is_extern, 1);
184+}
185+
186 /*----------------------------------------------------------------------*/
187
188 void free_node(struct string_list *node)
189@@ -236,6 +295,82 @@ static int equal_list(struct string_list
190 return !a && !b;
191 }
192
193+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
194+
195+struct string_list *read_node(FILE *f)
196+{
197+ char buffer[256];
198+ struct string_list node = {
199+ .string = buffer,
200+ .tag = SYM_NORMAL };
201+ int c;
202+
203+ while ((c = fgetc(f)) != EOF) {
204+ if (c == ' ') {
205+ if (node.string == buffer)
206+ continue;
207+ break;
208+ } else if (c == '\n') {
209+ if (node.string == buffer)
210+ return NULL;
211+ ungetc(c, f);
212+ break;
213+ }
214+ if (node.string >= buffer + sizeof(buffer) - 1) {
215+ fprintf(stderr, "Token too long\n");
216+ exit(1);
217+ }
218+ *node.string++ = c;
219+ }
220+ if (node.string == buffer)
221+ return NULL;
222+ *node.string = 0;
223+ node.string = buffer;
224+
225+ if (node.string[1] == '#') {
226+ int n;
227+
228+ for (n = 0; n < ARRAY_SIZE(symbol_type_name); n++) {
229+ if (node.string[0] == symbol_type_name[n][0]) {
230+ node.tag = n;
231+ node.string += 2;
232+ return copy_node(&node);
233+ }
234+ }
235+ fprintf(stderr, "Unknown type %c\n", node.string[0]);
236+ exit(1);
237+ }
238+ return copy_node(&node);
239+}
240+
241+static void read_reference(FILE *f)
242+{
243+ while (!feof(f)) {
244+ struct string_list *defn = NULL;
245+ struct string_list *sym, *def;
246+ int is_extern = 0;
247+
248+ sym = read_node(f);
249+ if (!sym)
250+ continue;
251+ def = read_node(f);
252+ if (def && def->tag == SYM_NORMAL &&
253+ !strcmp(def->string, "extern")) {
254+ is_extern = 1;
255+ free_node(def);
256+ def = read_node(f);
257+ }
258+ while (def) {
259+ def->next = defn;
260+ defn = def;
261+ def = read_node(f);
262+ }
263+ add_reference_symbol(xstrdup(sym->string), sym->tag,
264+ defn, is_extern);
265+ free_node(sym);
266+ }
267+}
268+
269 static void print_node(FILE * f, struct string_list *list)
270 {
271 if (list->tag != SYM_NORMAL) {
272@@ -311,6 +446,7 @@ static unsigned long expand_and_crc_sym(
273
274 case SYM_TYPEDEF:
275 subsym = find_symbol(cur->string, cur->tag);
276+ /* FIXME: Bad reference files can segfault here. */
277 if (subsym->expansion_trail) {
278 if (flag_dump_defs)
279 fprintf(debugfile, "%s ", cur->string);
280@@ -347,9 +483,22 @@ static unsigned long expand_and_crc_sym(
281 t = n;
282
283 n = xmalloc(sizeof(*n));
284- n->string = xstrdup("{ UNKNOWN }");
285+ n->string = xstrdup("{");
286+ n->tag = SYM_NORMAL;
287+ n->next = t;
288+ t = n;
289+
290+ n = xmalloc(sizeof(*n));
291+ n->string = xstrdup("UNKNOWN");
292+ n->tag = SYM_NORMAL;
293+ n->next = t;
294+ t = n;
295+
296+ n = xmalloc(sizeof(*n));
297+ n->string = xstrdup("}");
298 n->tag = SYM_NORMAL;
299 n->next = t;
300+ t = n;
301
302 subsym =
303 add_symbol(cur->string, cur->tag, n, 0);
304@@ -397,20 +546,42 @@ void export_symbol(const char *name)
305 error_with_pos("export undefined symbol %s", name);
306 else {
307 unsigned long crc;
308+ int has_changed = 0;
309
310 if (flag_dump_defs)
311 fprintf(debugfile, "Export %s == <", name);
312
313 expansion_trail = (struct symbol *)-1L;
314
315+ sym->expansion_trail = expansion_trail;
316+ expansion_trail = sym;
317 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
318
319 sym = expansion_trail;
320 while (sym != (struct symbol *)-1L) {
321 struct symbol *n = sym->expansion_trail;
322+
323+ if (sym->status != STATUS_UNCHANGED) {
324+ if (!has_changed) {
325+ print_location();
326+ fprintf(stderr, "%s: %s: modversion "
327+ "changed because of changes "
328+ "in ", flag_preserve ? "error" :
329+ "warning", name);
330+ } else
331+ fprintf(stderr, ", ");
332+ print_type_name(sym->type, sym->name);
333+ if (sym->status == STATUS_DEFINED)
334+ fprintf(stderr, " (became defined)");
335+ has_changed = 1;
336+ if (flag_preserve)
337+ errors++;
338+ }
339 sym->expansion_trail = 0;
340 sym = n;
341 }
342+ if (has_changed)
343+ fprintf(stderr, "\n");
344
345 if (flag_dump_defs)
346 fputs(">\n", debugfile);
347@@ -421,13 +592,26 @@ void export_symbol(const char *name)
348 }
349
350 /*----------------------------------------------------------------------*/
351+
352+static void print_location(void)
353+{
354+ fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
355+}
356+
357+static void print_type_name(enum symbol_type type, const char *name)
358+{
359+ if (type != SYM_NORMAL)
360+ fprintf(stderr, "%s %s", symbol_type_name[type], name);
361+ else
362+ fprintf(stderr, "%s", name);
363+}
364+
365 void error_with_pos(const char *fmt, ...)
366 {
367 va_list args;
368
369 if (flag_warnings) {
370- fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>",
371- cur_line);
372+ print_location();
373
374 va_start(args, fmt);
375 vfprintf(stderr, fmt, args);
376@@ -445,7 +629,9 @@ static void genksyms_usage(void)
377 " -a, --arch Select architecture\n"
378 " -d, --debug Increment the debug level (repeatable)\n"
379 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
380- " -T, --dump-types file Dump expanded types into file (for debugging only)\n"
381+ " -r, --reference file Read reference symbols from a file\n"
382+ " -T, --dump-types file Dump expanded types into file\n"
383+ " -p, --preserve Preserve reference modversions or fail\n"
384 " -w, --warnings Enable warnings\n"
385 " -q, --quiet Disable warnings (default)\n"
386 " -h, --help Print this message\n"
387@@ -454,7 +640,9 @@ static void genksyms_usage(void)
388 " -a Select architecture\n"
389 " -d Increment the debug level (repeatable)\n"
390 " -D Dump expanded symbol defs (for debugging only)\n"
391- " -T file Dump expanded types into file (for debugging only)\n"
392+ " -r file Read reference symbols from a file\n"
393+ " -T file Dump expanded types into file\n"
394+ " -p Preserve reference modversions or fail\n"
395 " -w Enable warnings\n"
396 " -q Disable warnings (default)\n"
397 " -h Print this message\n"
398@@ -465,7 +653,7 @@ static void genksyms_usage(void)
399
400 int main(int argc, char **argv)
401 {
402- FILE *dumpfile = NULL;
403+ FILE *dumpfile = NULL, *ref_file = NULL;
404 int o;
405
406 #ifdef __GNU_LIBRARY__
407@@ -475,16 +663,18 @@ int main(int argc, char **argv)
408 {"warnings", 0, 0, 'w'},
409 {"quiet", 0, 0, 'q'},
410 {"dump", 0, 0, 'D'},
411+ {"reference", 1, 0, 'r'},
412 {"dump-types", 1, 0, 'T'},
413+ {"preserve", 0, 0, 'p'},
414 {"version", 0, 0, 'V'},
415 {"help", 0, 0, 'h'},
416 {0, 0, 0, 0}
417 };
418
419- while ((o = getopt_long(argc, argv, "a:dwqVDT:h",
420+ while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph",
421 &long_opts[0], NULL)) != EOF)
422 #else /* __GNU_LIBRARY__ */
423- while ((o = getopt(argc, argv, "a:dwqVDT:h")) != EOF)
424+ while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF)
425 #endif /* __GNU_LIBRARY__ */
426 switch (o) {
427 case 'a':
428@@ -505,6 +695,14 @@ int main(int argc, char **argv)
429 case 'D':
430 flag_dump_defs = 1;
431 break;
432+ case 'r':
433+ flag_reference = 1;
434+ ref_file = fopen(optarg, "r");
435+ if (!ref_file) {
436+ perror(optarg);
437+ return 1;
438+ }
439+ break;
440 case 'T':
441 flag_dump_types = 1;
442 dumpfile = fopen(optarg, "w");
443@@ -513,6 +711,9 @@ int main(int argc, char **argv)
444 return 1;
445 }
446 break;
447+ case 'p':
448+ flag_preserve = 1;
449+ break;
450 case 'h':
451 genksyms_usage();
452 return 0;
453@@ -533,6 +734,9 @@ int main(int argc, char **argv)
454 /* setlinebuf(debugfile); */
455 }
456
457+ if (flag_reference)
458+ read_reference(ref_file);
459+
460 yyparse();
461
462 if (flag_dump_types && visited_symbols) {
463--- a/scripts/genksyms/genksyms.h
464+++ b/scripts/genksyms/genksyms.h
465@@ -29,6 +29,10 @@ enum symbol_type {
466 SYM_NORMAL, SYM_TYPEDEF, SYM_ENUM, SYM_STRUCT, SYM_UNION
467 };
468
469+enum symbol_status {
470+ STATUS_UNCHANGED, STATUS_DEFINED, STATUS_MODIFIED
471+};
472+
473 struct string_list {
474 struct string_list *next;
475 enum symbol_type tag;
476@@ -43,6 +47,8 @@ struct symbol {
477 struct symbol *expansion_trail;
478 struct symbol *visited;
479 int is_extern;
480+ int is_declared;
481+ enum symbol_status status;
482 };
483
484 typedef struct string_list **yystype;