Loading...
1/* Generate kernel symbol version hashes.
2 Copyright 1996, 1997 Linux International.
3
4 New implementation contributed by Richard Henderson <rth@tamu.edu>
5 Based on original work by Bjorn Ekwall <bj0rn@blox.se>
6
7 This file was part of the Linux modutils 2.4.22: moved back into the
8 kernel sources by Rusty Russell/Kai Germaschewski.
9
10 This program is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 2 of the License, or (at your
13 option) any later version.
14
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <assert.h>
29#include <stdarg.h>
30#ifdef __GNU_LIBRARY__
31#include <getopt.h>
32#endif /* __GNU_LIBRARY__ */
33
34#include "genksyms.h"
35/*----------------------------------------------------------------------*/
36
37#define HASH_BUCKETS 4096
38
39static struct symbol *symtab[HASH_BUCKETS];
40static FILE *debugfile;
41
42int cur_line = 1;
43char *cur_filename, *source_file;
44int in_source_file;
45
46static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
47 flag_preserve, flag_warnings;
48static const char *mod_prefix = "";
49
50static int errors;
51static int nsyms;
52
53static struct symbol *expansion_trail;
54static struct symbol *visited_symbols;
55
56static const struct {
57 int n;
58 const char *name;
59} symbol_types[] = {
60 [SYM_NORMAL] = { 0, NULL},
61 [SYM_TYPEDEF] = {'t', "typedef"},
62 [SYM_ENUM] = {'e', "enum"},
63 [SYM_STRUCT] = {'s', "struct"},
64 [SYM_UNION] = {'u', "union"},
65 [SYM_ENUM_CONST] = {'E', "enum constant"},
66};
67
68static int equal_list(struct string_list *a, struct string_list *b);
69static void print_list(FILE * f, struct string_list *list);
70static struct string_list *concat_list(struct string_list *start, ...);
71static struct string_list *mk_node(const char *string);
72static void print_location(void);
73static void print_type_name(enum symbol_type type, const char *name);
74
75/*----------------------------------------------------------------------*/
76
77static const unsigned int crctab32[] = {
78 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
79 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
80 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
81 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
82 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
83 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
84 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
85 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
86 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
87 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
88 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
89 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
90 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
91 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
92 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
93 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
94 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
95 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
96 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
97 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
98 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
99 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
100 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
101 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
102 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
103 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
104 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
105 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
106 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
107 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
108 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
109 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
110 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
111 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
112 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
113 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
114 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
115 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
116 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
117 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
118 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
119 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
120 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
121 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
122 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
123 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
124 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
125 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
126 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
127 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
128 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
129 0x2d02ef8dU
130};
131
132static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
133{
134 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
135}
136
137static unsigned long partial_crc32(const char *s, unsigned long crc)
138{
139 while (*s)
140 crc = partial_crc32_one(*s++, crc);
141 return crc;
142}
143
144static unsigned long crc32(const char *s)
145{
146 return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
147}
148
149/*----------------------------------------------------------------------*/
150
151static enum symbol_type map_to_ns(enum symbol_type t)
152{
153 switch (t) {
154 case SYM_ENUM_CONST:
155 case SYM_NORMAL:
156 case SYM_TYPEDEF:
157 return SYM_NORMAL;
158 case SYM_ENUM:
159 case SYM_STRUCT:
160 case SYM_UNION:
161 return SYM_STRUCT;
162 }
163 return t;
164}
165
166struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
167{
168 unsigned long h = crc32(name) % HASH_BUCKETS;
169 struct symbol *sym;
170
171 for (sym = symtab[h]; sym; sym = sym->hash_next)
172 if (map_to_ns(sym->type) == map_to_ns(ns) &&
173 strcmp(name, sym->name) == 0 &&
174 sym->is_declared)
175 break;
176
177 if (exact && sym && sym->type != ns)
178 return NULL;
179 return sym;
180}
181
182static int is_unknown_symbol(struct symbol *sym)
183{
184 struct string_list *defn;
185
186 return ((sym->type == SYM_STRUCT ||
187 sym->type == SYM_UNION ||
188 sym->type == SYM_ENUM) &&
189 (defn = sym->defn) && defn->tag == SYM_NORMAL &&
190 strcmp(defn->string, "}") == 0 &&
191 (defn = defn->next) && defn->tag == SYM_NORMAL &&
192 strcmp(defn->string, "UNKNOWN") == 0 &&
193 (defn = defn->next) && defn->tag == SYM_NORMAL &&
194 strcmp(defn->string, "{") == 0);
195}
196
197static struct symbol *__add_symbol(const char *name, enum symbol_type type,
198 struct string_list *defn, int is_extern,
199 int is_reference)
200{
201 unsigned long h;
202 struct symbol *sym;
203 enum symbol_status status = STATUS_UNCHANGED;
204 /* The parser adds symbols in the order their declaration completes,
205 * so it is safe to store the value of the previous enum constant in
206 * a static variable.
207 */
208 static int enum_counter;
209 static struct string_list *last_enum_expr;
210
211 if (type == SYM_ENUM_CONST) {
212 if (defn) {
213 free_list(last_enum_expr, NULL);
214 last_enum_expr = copy_list_range(defn, NULL);
215 enum_counter = 1;
216 } else {
217 struct string_list *expr;
218 char buf[20];
219
220 snprintf(buf, sizeof(buf), "%d", enum_counter++);
221 if (last_enum_expr) {
222 expr = copy_list_range(last_enum_expr, NULL);
223 defn = concat_list(mk_node("("),
224 expr,
225 mk_node(")"),
226 mk_node("+"),
227 mk_node(buf), NULL);
228 } else {
229 defn = mk_node(buf);
230 }
231 }
232 } else if (type == SYM_ENUM) {
233 free_list(last_enum_expr, NULL);
234 last_enum_expr = NULL;
235 enum_counter = 0;
236 if (!name)
237 /* Anonymous enum definition, nothing more to do */
238 return NULL;
239 }
240
241 h = crc32(name) % HASH_BUCKETS;
242 for (sym = symtab[h]; sym; sym = sym->hash_next) {
243 if (map_to_ns(sym->type) == map_to_ns(type) &&
244 strcmp(name, sym->name) == 0) {
245 if (is_reference)
246 /* fall through */ ;
247 else if (sym->type == type &&
248 equal_list(sym->defn, defn)) {
249 if (!sym->is_declared && sym->is_override) {
250 print_location();
251 print_type_name(type, name);
252 fprintf(stderr, " modversion is "
253 "unchanged\n");
254 }
255 sym->is_declared = 1;
256 return sym;
257 } else if (!sym->is_declared) {
258 if (sym->is_override && flag_preserve) {
259 print_location();
260 fprintf(stderr, "ignoring ");
261 print_type_name(type, name);
262 fprintf(stderr, " modversion change\n");
263 sym->is_declared = 1;
264 return sym;
265 } else {
266 status = is_unknown_symbol(sym) ?
267 STATUS_DEFINED : STATUS_MODIFIED;
268 }
269 } else {
270 error_with_pos("redefinition of %s", name);
271 return sym;
272 }
273 break;
274 }
275 }
276
277 if (sym) {
278 struct symbol **psym;
279
280 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
281 if (*psym == sym) {
282 *psym = sym->hash_next;
283 break;
284 }
285 }
286 --nsyms;
287 }
288
289 sym = xmalloc(sizeof(*sym));
290 sym->name = name;
291 sym->type = type;
292 sym->defn = defn;
293 sym->expansion_trail = NULL;
294 sym->visited = NULL;
295 sym->is_extern = is_extern;
296
297 sym->hash_next = symtab[h];
298 symtab[h] = sym;
299
300 sym->is_declared = !is_reference;
301 sym->status = status;
302 sym->is_override = 0;
303
304 if (flag_debug) {
305 if (symbol_types[type].name)
306 fprintf(debugfile, "Defn for %s %s == <",
307 symbol_types[type].name, name);
308 else
309 fprintf(debugfile, "Defn for type%d %s == <",
310 type, name);
311 if (is_extern)
312 fputs("extern ", debugfile);
313 print_list(debugfile, defn);
314 fputs(">\n", debugfile);
315 }
316
317 ++nsyms;
318 return sym;
319}
320
321struct symbol *add_symbol(const char *name, enum symbol_type type,
322 struct string_list *defn, int is_extern)
323{
324 return __add_symbol(name, type, defn, is_extern, 0);
325}
326
327static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
328 struct string_list *defn, int is_extern)
329{
330 return __add_symbol(name, type, defn, is_extern, 1);
331}
332
333/*----------------------------------------------------------------------*/
334
335void free_node(struct string_list *node)
336{
337 free(node->string);
338 free(node);
339}
340
341void free_list(struct string_list *s, struct string_list *e)
342{
343 while (s != e) {
344 struct string_list *next = s->next;
345 free_node(s);
346 s = next;
347 }
348}
349
350static struct string_list *mk_node(const char *string)
351{
352 struct string_list *newnode;
353
354 newnode = xmalloc(sizeof(*newnode));
355 newnode->string = xstrdup(string);
356 newnode->tag = SYM_NORMAL;
357 newnode->next = NULL;
358
359 return newnode;
360}
361
362static struct string_list *concat_list(struct string_list *start, ...)
363{
364 va_list ap;
365 struct string_list *n, *n2;
366
367 if (!start)
368 return NULL;
369 for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
370 for (n2 = n; n2->next; n2 = n2->next)
371 ;
372 n2->next = start;
373 start = n;
374 }
375 va_end(ap);
376 return start;
377}
378
379struct string_list *copy_node(struct string_list *node)
380{
381 struct string_list *newnode;
382
383 newnode = xmalloc(sizeof(*newnode));
384 newnode->string = xstrdup(node->string);
385 newnode->tag = node->tag;
386
387 return newnode;
388}
389
390struct string_list *copy_list_range(struct string_list *start,
391 struct string_list *end)
392{
393 struct string_list *res, *n;
394
395 if (start == end)
396 return NULL;
397 n = res = copy_node(start);
398 for (start = start->next; start != end; start = start->next) {
399 n->next = copy_node(start);
400 n = n->next;
401 }
402 n->next = NULL;
403 return res;
404}
405
406static int equal_list(struct string_list *a, struct string_list *b)
407{
408 while (a && b) {
409 if (a->tag != b->tag || strcmp(a->string, b->string))
410 return 0;
411 a = a->next;
412 b = b->next;
413 }
414
415 return !a && !b;
416}
417
418#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
419
420static struct string_list *read_node(FILE *f)
421{
422 char buffer[256];
423 struct string_list node = {
424 .string = buffer,
425 .tag = SYM_NORMAL };
426 int c, in_string = 0;
427
428 while ((c = fgetc(f)) != EOF) {
429 if (!in_string && c == ' ') {
430 if (node.string == buffer)
431 continue;
432 break;
433 } else if (c == '"') {
434 in_string = !in_string;
435 } else if (c == '\n') {
436 if (node.string == buffer)
437 return NULL;
438 ungetc(c, f);
439 break;
440 }
441 if (node.string >= buffer + sizeof(buffer) - 1) {
442 fprintf(stderr, "Token too long\n");
443 exit(1);
444 }
445 *node.string++ = c;
446 }
447 if (node.string == buffer)
448 return NULL;
449 *node.string = 0;
450 node.string = buffer;
451
452 if (node.string[1] == '#') {
453 size_t n;
454
455 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
456 if (node.string[0] == symbol_types[n].n) {
457 node.tag = n;
458 node.string += 2;
459 return copy_node(&node);
460 }
461 }
462 fprintf(stderr, "Unknown type %c\n", node.string[0]);
463 exit(1);
464 }
465 return copy_node(&node);
466}
467
468static void read_reference(FILE *f)
469{
470 while (!feof(f)) {
471 struct string_list *defn = NULL;
472 struct string_list *sym, *def;
473 int is_extern = 0, is_override = 0;
474 struct symbol *subsym;
475
476 sym = read_node(f);
477 if (sym && sym->tag == SYM_NORMAL &&
478 !strcmp(sym->string, "override")) {
479 is_override = 1;
480 free_node(sym);
481 sym = read_node(f);
482 }
483 if (!sym)
484 continue;
485 def = read_node(f);
486 if (def && def->tag == SYM_NORMAL &&
487 !strcmp(def->string, "extern")) {
488 is_extern = 1;
489 free_node(def);
490 def = read_node(f);
491 }
492 while (def) {
493 def->next = defn;
494 defn = def;
495 def = read_node(f);
496 }
497 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
498 defn, is_extern);
499 subsym->is_override = is_override;
500 free_node(sym);
501 }
502}
503
504static void print_node(FILE * f, struct string_list *list)
505{
506 if (symbol_types[list->tag].n) {
507 putc(symbol_types[list->tag].n, f);
508 putc('#', f);
509 }
510 fputs(list->string, f);
511}
512
513static void print_list(FILE * f, struct string_list *list)
514{
515 struct string_list **e, **b;
516 struct string_list *tmp, **tmp2;
517 int elem = 1;
518
519 if (list == NULL) {
520 fputs("(nil)", f);
521 return;
522 }
523
524 tmp = list;
525 while ((tmp = tmp->next) != NULL)
526 elem++;
527
528 b = alloca(elem * sizeof(*e));
529 e = b + elem;
530 tmp2 = e - 1;
531
532 (*tmp2--) = list;
533 while ((list = list->next) != NULL)
534 *(tmp2--) = list;
535
536 while (b != e) {
537 print_node(f, *b++);
538 putc(' ', f);
539 }
540}
541
542static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
543{
544 struct string_list *list = sym->defn;
545 struct string_list **e, **b;
546 struct string_list *tmp, **tmp2;
547 int elem = 1;
548
549 if (!list)
550 return crc;
551
552 tmp = list;
553 while ((tmp = tmp->next) != NULL)
554 elem++;
555
556 b = alloca(elem * sizeof(*e));
557 e = b + elem;
558 tmp2 = e - 1;
559
560 *(tmp2--) = list;
561 while ((list = list->next) != NULL)
562 *(tmp2--) = list;
563
564 while (b != e) {
565 struct string_list *cur;
566 struct symbol *subsym;
567
568 cur = *(b++);
569 switch (cur->tag) {
570 case SYM_NORMAL:
571 if (flag_dump_defs)
572 fprintf(debugfile, "%s ", cur->string);
573 crc = partial_crc32(cur->string, crc);
574 crc = partial_crc32_one(' ', crc);
575 break;
576
577 case SYM_ENUM_CONST:
578 case SYM_TYPEDEF:
579 subsym = find_symbol(cur->string, cur->tag, 0);
580 /* FIXME: Bad reference files can segfault here. */
581 if (subsym->expansion_trail) {
582 if (flag_dump_defs)
583 fprintf(debugfile, "%s ", cur->string);
584 crc = partial_crc32(cur->string, crc);
585 crc = partial_crc32_one(' ', crc);
586 } else {
587 subsym->expansion_trail = expansion_trail;
588 expansion_trail = subsym;
589 crc = expand_and_crc_sym(subsym, crc);
590 }
591 break;
592
593 case SYM_STRUCT:
594 case SYM_UNION:
595 case SYM_ENUM:
596 subsym = find_symbol(cur->string, cur->tag, 0);
597 if (!subsym) {
598 struct string_list *n;
599
600 error_with_pos("expand undefined %s %s",
601 symbol_types[cur->tag].name,
602 cur->string);
603 n = concat_list(mk_node
604 (symbol_types[cur->tag].name),
605 mk_node(cur->string),
606 mk_node("{"),
607 mk_node("UNKNOWN"),
608 mk_node("}"), NULL);
609 subsym =
610 add_symbol(cur->string, cur->tag, n, 0);
611 }
612 if (subsym->expansion_trail) {
613 if (flag_dump_defs) {
614 fprintf(debugfile, "%s %s ",
615 symbol_types[cur->tag].name,
616 cur->string);
617 }
618
619 crc = partial_crc32(symbol_types[cur->tag].name,
620 crc);
621 crc = partial_crc32_one(' ', crc);
622 crc = partial_crc32(cur->string, crc);
623 crc = partial_crc32_one(' ', crc);
624 } else {
625 subsym->expansion_trail = expansion_trail;
626 expansion_trail = subsym;
627 crc = expand_and_crc_sym(subsym, crc);
628 }
629 break;
630 }
631 }
632
633 {
634 static struct symbol **end = &visited_symbols;
635
636 if (!sym->visited) {
637 *end = sym;
638 end = &sym->visited;
639 sym->visited = (struct symbol *)-1L;
640 }
641 }
642
643 return crc;
644}
645
646void export_symbol(const char *name)
647{
648 struct symbol *sym;
649
650 sym = find_symbol(name, SYM_NORMAL, 0);
651 if (!sym)
652 error_with_pos("export undefined symbol %s", name);
653 else {
654 unsigned long crc;
655 int has_changed = 0;
656
657 if (flag_dump_defs)
658 fprintf(debugfile, "Export %s == <", name);
659
660 expansion_trail = (struct symbol *)-1L;
661
662 sym->expansion_trail = expansion_trail;
663 expansion_trail = sym;
664 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
665
666 sym = expansion_trail;
667 while (sym != (struct symbol *)-1L) {
668 struct symbol *n = sym->expansion_trail;
669
670 if (sym->status != STATUS_UNCHANGED) {
671 if (!has_changed) {
672 print_location();
673 fprintf(stderr, "%s: %s: modversion "
674 "changed because of changes "
675 "in ", flag_preserve ? "error" :
676 "warning", name);
677 } else
678 fprintf(stderr, ", ");
679 print_type_name(sym->type, sym->name);
680 if (sym->status == STATUS_DEFINED)
681 fprintf(stderr, " (became defined)");
682 has_changed = 1;
683 if (flag_preserve)
684 errors++;
685 }
686 sym->expansion_trail = 0;
687 sym = n;
688 }
689 if (has_changed)
690 fprintf(stderr, "\n");
691
692 if (flag_dump_defs)
693 fputs(">\n", debugfile);
694
695 /* Used as a linker script. */
696 printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
697 }
698}
699
700/*----------------------------------------------------------------------*/
701
702static void print_location(void)
703{
704 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
705}
706
707static void print_type_name(enum symbol_type type, const char *name)
708{
709 if (symbol_types[type].name)
710 fprintf(stderr, "%s %s", symbol_types[type].name, name);
711 else
712 fprintf(stderr, "%s", name);
713}
714
715void error_with_pos(const char *fmt, ...)
716{
717 va_list args;
718
719 if (flag_warnings) {
720 print_location();
721
722 va_start(args, fmt);
723 vfprintf(stderr, fmt, args);
724 va_end(args);
725 putc('\n', stderr);
726
727 errors++;
728 }
729}
730
731static void genksyms_usage(void)
732{
733 fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
734#ifdef __GNU_LIBRARY__
735 " -s, --symbol-prefix Select symbol prefix\n"
736 " -d, --debug Increment the debug level (repeatable)\n"
737 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
738 " -r, --reference file Read reference symbols from a file\n"
739 " -T, --dump-types file Dump expanded types into file\n"
740 " -p, --preserve Preserve reference modversions or fail\n"
741 " -w, --warnings Enable warnings\n"
742 " -q, --quiet Disable warnings (default)\n"
743 " -h, --help Print this message\n"
744 " -V, --version Print the release version\n"
745#else /* __GNU_LIBRARY__ */
746 " -s Select symbol prefix\n"
747 " -d Increment the debug level (repeatable)\n"
748 " -D Dump expanded symbol defs (for debugging only)\n"
749 " -r file Read reference symbols from a file\n"
750 " -T file Dump expanded types into file\n"
751 " -p Preserve reference modversions or fail\n"
752 " -w Enable warnings\n"
753 " -q Disable warnings (default)\n"
754 " -h Print this message\n"
755 " -V Print the release version\n"
756#endif /* __GNU_LIBRARY__ */
757 , stderr);
758}
759
760int main(int argc, char **argv)
761{
762 FILE *dumpfile = NULL, *ref_file = NULL;
763 int o;
764
765#ifdef __GNU_LIBRARY__
766 struct option long_opts[] = {
767 {"symbol-prefix", 1, 0, 's'},
768 {"debug", 0, 0, 'd'},
769 {"warnings", 0, 0, 'w'},
770 {"quiet", 0, 0, 'q'},
771 {"dump", 0, 0, 'D'},
772 {"reference", 1, 0, 'r'},
773 {"dump-types", 1, 0, 'T'},
774 {"preserve", 0, 0, 'p'},
775 {"version", 0, 0, 'V'},
776 {"help", 0, 0, 'h'},
777 {0, 0, 0, 0}
778 };
779
780 while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
781 &long_opts[0], NULL)) != EOF)
782#else /* __GNU_LIBRARY__ */
783 while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF)
784#endif /* __GNU_LIBRARY__ */
785 switch (o) {
786 case 's':
787 mod_prefix = optarg;
788 break;
789 case 'd':
790 flag_debug++;
791 break;
792 case 'w':
793 flag_warnings = 1;
794 break;
795 case 'q':
796 flag_warnings = 0;
797 break;
798 case 'V':
799 fputs("genksyms version 2.5.60\n", stderr);
800 break;
801 case 'D':
802 flag_dump_defs = 1;
803 break;
804 case 'r':
805 flag_reference = 1;
806 ref_file = fopen(optarg, "r");
807 if (!ref_file) {
808 perror(optarg);
809 return 1;
810 }
811 break;
812 case 'T':
813 flag_dump_types = 1;
814 dumpfile = fopen(optarg, "w");
815 if (!dumpfile) {
816 perror(optarg);
817 return 1;
818 }
819 break;
820 case 'p':
821 flag_preserve = 1;
822 break;
823 case 'h':
824 genksyms_usage();
825 return 0;
826 default:
827 genksyms_usage();
828 return 1;
829 }
830 {
831 extern int yydebug;
832 extern int yy_flex_debug;
833
834 yydebug = (flag_debug > 1);
835 yy_flex_debug = (flag_debug > 2);
836
837 debugfile = stderr;
838 /* setlinebuf(debugfile); */
839 }
840
841 if (flag_reference) {
842 read_reference(ref_file);
843 fclose(ref_file);
844 }
845
846 yyparse();
847
848 if (flag_dump_types && visited_symbols) {
849 while (visited_symbols != (struct symbol *)-1L) {
850 struct symbol *sym = visited_symbols;
851
852 if (sym->is_override)
853 fputs("override ", dumpfile);
854 if (symbol_types[sym->type].n) {
855 putc(symbol_types[sym->type].n, dumpfile);
856 putc('#', dumpfile);
857 }
858 fputs(sym->name, dumpfile);
859 putc(' ', dumpfile);
860 if (sym->is_extern)
861 fputs("extern ", dumpfile);
862 print_list(dumpfile, sym->defn);
863 putc('\n', dumpfile);
864
865 visited_symbols = sym->visited;
866 sym->visited = NULL;
867 }
868 }
869
870 if (flag_debug) {
871 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
872 nsyms, HASH_BUCKETS,
873 (double)nsyms / (double)HASH_BUCKETS);
874 }
875
876 return errors != 0;
877}
1// SPDX-License-Identifier: GPL-2.0-or-later
2/* Generate kernel symbol version hashes.
3 Copyright 1996, 1997 Linux International.
4
5 New implementation contributed by Richard Henderson <rth@tamu.edu>
6 Based on original work by Bjorn Ekwall <bj0rn@blox.se>
7
8 This file was part of the Linux modutils 2.4.22: moved back into the
9 kernel sources by Rusty Russell/Kai Germaschewski.
10
11 */
12
13#include <stdio.h>
14#include <string.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <assert.h>
18#include <stdarg.h>
19#ifdef __GNU_LIBRARY__
20#include <getopt.h>
21#endif /* __GNU_LIBRARY__ */
22
23#include "genksyms.h"
24/*----------------------------------------------------------------------*/
25
26#define HASH_BUCKETS 4096
27
28static struct symbol *symtab[HASH_BUCKETS];
29static FILE *debugfile;
30
31int cur_line = 1;
32char *cur_filename;
33int in_source_file;
34
35static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
36 flag_preserve, flag_warnings;
37
38static int errors;
39static int nsyms;
40
41static struct symbol *expansion_trail;
42static struct symbol *visited_symbols;
43
44static const struct {
45 int n;
46 const char *name;
47} symbol_types[] = {
48 [SYM_NORMAL] = { 0, NULL},
49 [SYM_TYPEDEF] = {'t', "typedef"},
50 [SYM_ENUM] = {'e', "enum"},
51 [SYM_STRUCT] = {'s', "struct"},
52 [SYM_UNION] = {'u', "union"},
53 [SYM_ENUM_CONST] = {'E', "enum constant"},
54};
55
56static int equal_list(struct string_list *a, struct string_list *b);
57static void print_list(FILE * f, struct string_list *list);
58static struct string_list *concat_list(struct string_list *start, ...);
59static struct string_list *mk_node(const char *string);
60static void print_location(void);
61static void print_type_name(enum symbol_type type, const char *name);
62
63/*----------------------------------------------------------------------*/
64
65static const unsigned int crctab32[] = {
66 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
67 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
68 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
69 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
70 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
71 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
72 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
73 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
74 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
75 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
76 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
77 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
78 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
79 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
80 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
81 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
82 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
83 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
84 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
85 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
86 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
87 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
88 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
89 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
90 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
91 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
92 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
93 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
94 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
95 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
96 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
97 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
98 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
99 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
100 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
101 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
102 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
103 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
104 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
105 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
106 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
107 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
108 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
109 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
110 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
111 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
112 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
113 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
114 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
115 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
116 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
117 0x2d02ef8dU
118};
119
120static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
121{
122 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
123}
124
125static unsigned long partial_crc32(const char *s, unsigned long crc)
126{
127 while (*s)
128 crc = partial_crc32_one(*s++, crc);
129 return crc;
130}
131
132static unsigned long crc32(const char *s)
133{
134 return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
135}
136
137/*----------------------------------------------------------------------*/
138
139static enum symbol_type map_to_ns(enum symbol_type t)
140{
141 switch (t) {
142 case SYM_ENUM_CONST:
143 case SYM_NORMAL:
144 case SYM_TYPEDEF:
145 return SYM_NORMAL;
146 case SYM_ENUM:
147 case SYM_STRUCT:
148 case SYM_UNION:
149 return SYM_STRUCT;
150 }
151 return t;
152}
153
154struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
155{
156 unsigned long h = crc32(name) % HASH_BUCKETS;
157 struct symbol *sym;
158
159 for (sym = symtab[h]; sym; sym = sym->hash_next)
160 if (map_to_ns(sym->type) == map_to_ns(ns) &&
161 strcmp(name, sym->name) == 0 &&
162 sym->is_declared)
163 break;
164
165 if (exact && sym && sym->type != ns)
166 return NULL;
167 return sym;
168}
169
170static int is_unknown_symbol(struct symbol *sym)
171{
172 struct string_list *defn;
173
174 return ((sym->type == SYM_STRUCT ||
175 sym->type == SYM_UNION ||
176 sym->type == SYM_ENUM) &&
177 (defn = sym->defn) && defn->tag == SYM_NORMAL &&
178 strcmp(defn->string, "}") == 0 &&
179 (defn = defn->next) && defn->tag == SYM_NORMAL &&
180 strcmp(defn->string, "UNKNOWN") == 0 &&
181 (defn = defn->next) && defn->tag == SYM_NORMAL &&
182 strcmp(defn->string, "{") == 0);
183}
184
185static struct symbol *__add_symbol(const char *name, enum symbol_type type,
186 struct string_list *defn, int is_extern,
187 int is_reference)
188{
189 unsigned long h;
190 struct symbol *sym;
191 enum symbol_status status = STATUS_UNCHANGED;
192 /* The parser adds symbols in the order their declaration completes,
193 * so it is safe to store the value of the previous enum constant in
194 * a static variable.
195 */
196 static int enum_counter;
197 static struct string_list *last_enum_expr;
198
199 if (type == SYM_ENUM_CONST) {
200 if (defn) {
201 free_list(last_enum_expr, NULL);
202 last_enum_expr = copy_list_range(defn, NULL);
203 enum_counter = 1;
204 } else {
205 struct string_list *expr;
206 char buf[20];
207
208 snprintf(buf, sizeof(buf), "%d", enum_counter++);
209 if (last_enum_expr) {
210 expr = copy_list_range(last_enum_expr, NULL);
211 defn = concat_list(mk_node("("),
212 expr,
213 mk_node(")"),
214 mk_node("+"),
215 mk_node(buf), NULL);
216 } else {
217 defn = mk_node(buf);
218 }
219 }
220 } else if (type == SYM_ENUM) {
221 free_list(last_enum_expr, NULL);
222 last_enum_expr = NULL;
223 enum_counter = 0;
224 if (!name)
225 /* Anonymous enum definition, nothing more to do */
226 return NULL;
227 }
228
229 h = crc32(name) % HASH_BUCKETS;
230 for (sym = symtab[h]; sym; sym = sym->hash_next) {
231 if (map_to_ns(sym->type) == map_to_ns(type) &&
232 strcmp(name, sym->name) == 0) {
233 if (is_reference)
234 /* fall through */ ;
235 else if (sym->type == type &&
236 equal_list(sym->defn, defn)) {
237 if (!sym->is_declared && sym->is_override) {
238 print_location();
239 print_type_name(type, name);
240 fprintf(stderr, " modversion is "
241 "unchanged\n");
242 }
243 sym->is_declared = 1;
244 return sym;
245 } else if (!sym->is_declared) {
246 if (sym->is_override && flag_preserve) {
247 print_location();
248 fprintf(stderr, "ignoring ");
249 print_type_name(type, name);
250 fprintf(stderr, " modversion change\n");
251 sym->is_declared = 1;
252 return sym;
253 } else {
254 status = is_unknown_symbol(sym) ?
255 STATUS_DEFINED : STATUS_MODIFIED;
256 }
257 } else {
258 error_with_pos("redefinition of %s", name);
259 return sym;
260 }
261 break;
262 }
263 }
264
265 if (sym) {
266 struct symbol **psym;
267
268 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
269 if (*psym == sym) {
270 *psym = sym->hash_next;
271 break;
272 }
273 }
274 --nsyms;
275 }
276
277 sym = xmalloc(sizeof(*sym));
278 sym->name = name;
279 sym->type = type;
280 sym->defn = defn;
281 sym->expansion_trail = NULL;
282 sym->visited = NULL;
283 sym->is_extern = is_extern;
284
285 sym->hash_next = symtab[h];
286 symtab[h] = sym;
287
288 sym->is_declared = !is_reference;
289 sym->status = status;
290 sym->is_override = 0;
291
292 if (flag_debug) {
293 if (symbol_types[type].name)
294 fprintf(debugfile, "Defn for %s %s == <",
295 symbol_types[type].name, name);
296 else
297 fprintf(debugfile, "Defn for type%d %s == <",
298 type, name);
299 if (is_extern)
300 fputs("extern ", debugfile);
301 print_list(debugfile, defn);
302 fputs(">\n", debugfile);
303 }
304
305 ++nsyms;
306 return sym;
307}
308
309struct symbol *add_symbol(const char *name, enum symbol_type type,
310 struct string_list *defn, int is_extern)
311{
312 return __add_symbol(name, type, defn, is_extern, 0);
313}
314
315static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
316 struct string_list *defn, int is_extern)
317{
318 return __add_symbol(name, type, defn, is_extern, 1);
319}
320
321/*----------------------------------------------------------------------*/
322
323void free_node(struct string_list *node)
324{
325 free(node->string);
326 free(node);
327}
328
329void free_list(struct string_list *s, struct string_list *e)
330{
331 while (s != e) {
332 struct string_list *next = s->next;
333 free_node(s);
334 s = next;
335 }
336}
337
338static struct string_list *mk_node(const char *string)
339{
340 struct string_list *newnode;
341
342 newnode = xmalloc(sizeof(*newnode));
343 newnode->string = xstrdup(string);
344 newnode->tag = SYM_NORMAL;
345 newnode->next = NULL;
346
347 return newnode;
348}
349
350static struct string_list *concat_list(struct string_list *start, ...)
351{
352 va_list ap;
353 struct string_list *n, *n2;
354
355 if (!start)
356 return NULL;
357 for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
358 for (n2 = n; n2->next; n2 = n2->next)
359 ;
360 n2->next = start;
361 start = n;
362 }
363 va_end(ap);
364 return start;
365}
366
367struct string_list *copy_node(struct string_list *node)
368{
369 struct string_list *newnode;
370
371 newnode = xmalloc(sizeof(*newnode));
372 newnode->string = xstrdup(node->string);
373 newnode->tag = node->tag;
374
375 return newnode;
376}
377
378struct string_list *copy_list_range(struct string_list *start,
379 struct string_list *end)
380{
381 struct string_list *res, *n;
382
383 if (start == end)
384 return NULL;
385 n = res = copy_node(start);
386 for (start = start->next; start != end; start = start->next) {
387 n->next = copy_node(start);
388 n = n->next;
389 }
390 n->next = NULL;
391 return res;
392}
393
394static int equal_list(struct string_list *a, struct string_list *b)
395{
396 while (a && b) {
397 if (a->tag != b->tag || strcmp(a->string, b->string))
398 return 0;
399 a = a->next;
400 b = b->next;
401 }
402
403 return !a && !b;
404}
405
406#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
407
408static struct string_list *read_node(FILE *f)
409{
410 char buffer[256];
411 struct string_list node = {
412 .string = buffer,
413 .tag = SYM_NORMAL };
414 int c, in_string = 0;
415
416 while ((c = fgetc(f)) != EOF) {
417 if (!in_string && c == ' ') {
418 if (node.string == buffer)
419 continue;
420 break;
421 } else if (c == '"') {
422 in_string = !in_string;
423 } else if (c == '\n') {
424 if (node.string == buffer)
425 return NULL;
426 ungetc(c, f);
427 break;
428 }
429 if (node.string >= buffer + sizeof(buffer) - 1) {
430 fprintf(stderr, "Token too long\n");
431 exit(1);
432 }
433 *node.string++ = c;
434 }
435 if (node.string == buffer)
436 return NULL;
437 *node.string = 0;
438 node.string = buffer;
439
440 if (node.string[1] == '#') {
441 size_t n;
442
443 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
444 if (node.string[0] == symbol_types[n].n) {
445 node.tag = n;
446 node.string += 2;
447 return copy_node(&node);
448 }
449 }
450 fprintf(stderr, "Unknown type %c\n", node.string[0]);
451 exit(1);
452 }
453 return copy_node(&node);
454}
455
456static void read_reference(FILE *f)
457{
458 while (!feof(f)) {
459 struct string_list *defn = NULL;
460 struct string_list *sym, *def;
461 int is_extern = 0, is_override = 0;
462 struct symbol *subsym;
463
464 sym = read_node(f);
465 if (sym && sym->tag == SYM_NORMAL &&
466 !strcmp(sym->string, "override")) {
467 is_override = 1;
468 free_node(sym);
469 sym = read_node(f);
470 }
471 if (!sym)
472 continue;
473 def = read_node(f);
474 if (def && def->tag == SYM_NORMAL &&
475 !strcmp(def->string, "extern")) {
476 is_extern = 1;
477 free_node(def);
478 def = read_node(f);
479 }
480 while (def) {
481 def->next = defn;
482 defn = def;
483 def = read_node(f);
484 }
485 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
486 defn, is_extern);
487 subsym->is_override = is_override;
488 free_node(sym);
489 }
490}
491
492static void print_node(FILE * f, struct string_list *list)
493{
494 if (symbol_types[list->tag].n) {
495 putc(symbol_types[list->tag].n, f);
496 putc('#', f);
497 }
498 fputs(list->string, f);
499}
500
501static void print_list(FILE * f, struct string_list *list)
502{
503 struct string_list **e, **b;
504 struct string_list *tmp, **tmp2;
505 int elem = 1;
506
507 if (list == NULL) {
508 fputs("(nil)", f);
509 return;
510 }
511
512 tmp = list;
513 while ((tmp = tmp->next) != NULL)
514 elem++;
515
516 b = alloca(elem * sizeof(*e));
517 e = b + elem;
518 tmp2 = e - 1;
519
520 (*tmp2--) = list;
521 while ((list = list->next) != NULL)
522 *(tmp2--) = list;
523
524 while (b != e) {
525 print_node(f, *b++);
526 putc(' ', f);
527 }
528}
529
530static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
531{
532 struct string_list *list = sym->defn;
533 struct string_list **e, **b;
534 struct string_list *tmp, **tmp2;
535 int elem = 1;
536
537 if (!list)
538 return crc;
539
540 tmp = list;
541 while ((tmp = tmp->next) != NULL)
542 elem++;
543
544 b = alloca(elem * sizeof(*e));
545 e = b + elem;
546 tmp2 = e - 1;
547
548 *(tmp2--) = list;
549 while ((list = list->next) != NULL)
550 *(tmp2--) = list;
551
552 while (b != e) {
553 struct string_list *cur;
554 struct symbol *subsym;
555
556 cur = *(b++);
557 switch (cur->tag) {
558 case SYM_NORMAL:
559 if (flag_dump_defs)
560 fprintf(debugfile, "%s ", cur->string);
561 crc = partial_crc32(cur->string, crc);
562 crc = partial_crc32_one(' ', crc);
563 break;
564
565 case SYM_ENUM_CONST:
566 case SYM_TYPEDEF:
567 subsym = find_symbol(cur->string, cur->tag, 0);
568 /* FIXME: Bad reference files can segfault here. */
569 if (subsym->expansion_trail) {
570 if (flag_dump_defs)
571 fprintf(debugfile, "%s ", cur->string);
572 crc = partial_crc32(cur->string, crc);
573 crc = partial_crc32_one(' ', crc);
574 } else {
575 subsym->expansion_trail = expansion_trail;
576 expansion_trail = subsym;
577 crc = expand_and_crc_sym(subsym, crc);
578 }
579 break;
580
581 case SYM_STRUCT:
582 case SYM_UNION:
583 case SYM_ENUM:
584 subsym = find_symbol(cur->string, cur->tag, 0);
585 if (!subsym) {
586 struct string_list *n;
587
588 error_with_pos("expand undefined %s %s",
589 symbol_types[cur->tag].name,
590 cur->string);
591 n = concat_list(mk_node
592 (symbol_types[cur->tag].name),
593 mk_node(cur->string),
594 mk_node("{"),
595 mk_node("UNKNOWN"),
596 mk_node("}"), NULL);
597 subsym =
598 add_symbol(cur->string, cur->tag, n, 0);
599 }
600 if (subsym->expansion_trail) {
601 if (flag_dump_defs) {
602 fprintf(debugfile, "%s %s ",
603 symbol_types[cur->tag].name,
604 cur->string);
605 }
606
607 crc = partial_crc32(symbol_types[cur->tag].name,
608 crc);
609 crc = partial_crc32_one(' ', crc);
610 crc = partial_crc32(cur->string, crc);
611 crc = partial_crc32_one(' ', crc);
612 } else {
613 subsym->expansion_trail = expansion_trail;
614 expansion_trail = subsym;
615 crc = expand_and_crc_sym(subsym, crc);
616 }
617 break;
618 }
619 }
620
621 {
622 static struct symbol **end = &visited_symbols;
623
624 if (!sym->visited) {
625 *end = sym;
626 end = &sym->visited;
627 sym->visited = (struct symbol *)-1L;
628 }
629 }
630
631 return crc;
632}
633
634void export_symbol(const char *name)
635{
636 struct symbol *sym;
637
638 sym = find_symbol(name, SYM_NORMAL, 0);
639 if (!sym)
640 error_with_pos("export undefined symbol %s", name);
641 else {
642 unsigned long crc;
643 int has_changed = 0;
644
645 if (flag_dump_defs)
646 fprintf(debugfile, "Export %s == <", name);
647
648 expansion_trail = (struct symbol *)-1L;
649
650 sym->expansion_trail = expansion_trail;
651 expansion_trail = sym;
652 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
653
654 sym = expansion_trail;
655 while (sym != (struct symbol *)-1L) {
656 struct symbol *n = sym->expansion_trail;
657
658 if (sym->status != STATUS_UNCHANGED) {
659 if (!has_changed) {
660 print_location();
661 fprintf(stderr, "%s: %s: modversion "
662 "changed because of changes "
663 "in ", flag_preserve ? "error" :
664 "warning", name);
665 } else
666 fprintf(stderr, ", ");
667 print_type_name(sym->type, sym->name);
668 if (sym->status == STATUS_DEFINED)
669 fprintf(stderr, " (became defined)");
670 has_changed = 1;
671 if (flag_preserve)
672 errors++;
673 }
674 sym->expansion_trail = 0;
675 sym = n;
676 }
677 if (has_changed)
678 fprintf(stderr, "\n");
679
680 if (flag_dump_defs)
681 fputs(">\n", debugfile);
682
683 printf("#SYMVER %s 0x%08lx\n", name, crc);
684 }
685}
686
687/*----------------------------------------------------------------------*/
688
689static void print_location(void)
690{
691 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
692}
693
694static void print_type_name(enum symbol_type type, const char *name)
695{
696 if (symbol_types[type].name)
697 fprintf(stderr, "%s %s", symbol_types[type].name, name);
698 else
699 fprintf(stderr, "%s", name);
700}
701
702void error_with_pos(const char *fmt, ...)
703{
704 va_list args;
705
706 if (flag_warnings) {
707 print_location();
708
709 va_start(args, fmt);
710 vfprintf(stderr, fmt, args);
711 va_end(args);
712 putc('\n', stderr);
713
714 errors++;
715 }
716}
717
718static void genksyms_usage(void)
719{
720 fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
721#ifdef __GNU_LIBRARY__
722 " -s, --symbol-prefix Select symbol prefix\n"
723 " -d, --debug Increment the debug level (repeatable)\n"
724 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
725 " -r, --reference file Read reference symbols from a file\n"
726 " -T, --dump-types file Dump expanded types into file\n"
727 " -p, --preserve Preserve reference modversions or fail\n"
728 " -w, --warnings Enable warnings\n"
729 " -q, --quiet Disable warnings (default)\n"
730 " -h, --help Print this message\n"
731 " -V, --version Print the release version\n"
732#else /* __GNU_LIBRARY__ */
733 " -s Select symbol prefix\n"
734 " -d Increment the debug level (repeatable)\n"
735 " -D Dump expanded symbol defs (for debugging only)\n"
736 " -r file Read reference symbols from a file\n"
737 " -T file Dump expanded types into file\n"
738 " -p Preserve reference modversions or fail\n"
739 " -w Enable warnings\n"
740 " -q Disable warnings (default)\n"
741 " -h Print this message\n"
742 " -V Print the release version\n"
743#endif /* __GNU_LIBRARY__ */
744 , stderr);
745}
746
747int main(int argc, char **argv)
748{
749 FILE *dumpfile = NULL, *ref_file = NULL;
750 int o;
751
752#ifdef __GNU_LIBRARY__
753 struct option long_opts[] = {
754 {"debug", 0, 0, 'd'},
755 {"warnings", 0, 0, 'w'},
756 {"quiet", 0, 0, 'q'},
757 {"dump", 0, 0, 'D'},
758 {"reference", 1, 0, 'r'},
759 {"dump-types", 1, 0, 'T'},
760 {"preserve", 0, 0, 'p'},
761 {"version", 0, 0, 'V'},
762 {"help", 0, 0, 'h'},
763 {0, 0, 0, 0}
764 };
765
766 while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
767 &long_opts[0], NULL)) != EOF)
768#else /* __GNU_LIBRARY__ */
769 while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF)
770#endif /* __GNU_LIBRARY__ */
771 switch (o) {
772 case 'd':
773 flag_debug++;
774 break;
775 case 'w':
776 flag_warnings = 1;
777 break;
778 case 'q':
779 flag_warnings = 0;
780 break;
781 case 'V':
782 fputs("genksyms version 2.5.60\n", stderr);
783 break;
784 case 'D':
785 flag_dump_defs = 1;
786 break;
787 case 'r':
788 flag_reference = 1;
789 ref_file = fopen(optarg, "r");
790 if (!ref_file) {
791 perror(optarg);
792 return 1;
793 }
794 break;
795 case 'T':
796 flag_dump_types = 1;
797 dumpfile = fopen(optarg, "w");
798 if (!dumpfile) {
799 perror(optarg);
800 return 1;
801 }
802 break;
803 case 'p':
804 flag_preserve = 1;
805 break;
806 case 'h':
807 genksyms_usage();
808 return 0;
809 default:
810 genksyms_usage();
811 return 1;
812 }
813 {
814 extern int yydebug;
815 extern int yy_flex_debug;
816
817 yydebug = (flag_debug > 1);
818 yy_flex_debug = (flag_debug > 2);
819
820 debugfile = stderr;
821 /* setlinebuf(debugfile); */
822 }
823
824 if (flag_reference) {
825 read_reference(ref_file);
826 fclose(ref_file);
827 }
828
829 yyparse();
830
831 if (flag_dump_types && visited_symbols) {
832 while (visited_symbols != (struct symbol *)-1L) {
833 struct symbol *sym = visited_symbols;
834
835 if (sym->is_override)
836 fputs("override ", dumpfile);
837 if (symbol_types[sym->type].n) {
838 putc(symbol_types[sym->type].n, dumpfile);
839 putc('#', dumpfile);
840 }
841 fputs(sym->name, dumpfile);
842 putc(' ', dumpfile);
843 if (sym->is_extern)
844 fputs("extern ", dumpfile);
845 print_list(dumpfile, sym->defn);
846 putc('\n', dumpfile);
847
848 visited_symbols = sym->visited;
849 sym->visited = NULL;
850 }
851 }
852
853 if (flag_debug) {
854 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
855 nsyms, HASH_BUCKETS,
856 (double)nsyms / (double)HASH_BUCKETS);
857 }
858
859 if (dumpfile)
860 fclose(dumpfile);
861
862 return errors != 0;
863}