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