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, flag_rel_crcs;
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(!flag_rel_crcs ? "%s__crc_%s = 0x%08lx;\n" :
697 "SECTIONS { .rodata : ALIGN(4) { "
698 "%s__crc_%s = .; LONG(0x%08lx); } }\n",
699 mod_prefix, name, crc);
700 }
701}
702
703/*----------------------------------------------------------------------*/
704
705static void print_location(void)
706{
707 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
708}
709
710static void print_type_name(enum symbol_type type, const char *name)
711{
712 if (symbol_types[type].name)
713 fprintf(stderr, "%s %s", symbol_types[type].name, name);
714 else
715 fprintf(stderr, "%s", name);
716}
717
718void error_with_pos(const char *fmt, ...)
719{
720 va_list args;
721
722 if (flag_warnings) {
723 print_location();
724
725 va_start(args, fmt);
726 vfprintf(stderr, fmt, args);
727 va_end(args);
728 putc('\n', stderr);
729
730 errors++;
731 }
732}
733
734static void genksyms_usage(void)
735{
736 fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
737#ifdef __GNU_LIBRARY__
738 " -s, --symbol-prefix Select symbol prefix\n"
739 " -d, --debug Increment the debug level (repeatable)\n"
740 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
741 " -r, --reference file Read reference symbols from a file\n"
742 " -T, --dump-types file Dump expanded types into file\n"
743 " -p, --preserve Preserve reference modversions or fail\n"
744 " -w, --warnings Enable warnings\n"
745 " -q, --quiet Disable warnings (default)\n"
746 " -h, --help Print this message\n"
747 " -V, --version Print the release version\n"
748 " -R, --relative-crc Emit section relative symbol CRCs\n"
749#else /* __GNU_LIBRARY__ */
750 " -s Select symbol prefix\n"
751 " -d Increment the debug level (repeatable)\n"
752 " -D Dump expanded symbol defs (for debugging only)\n"
753 " -r file Read reference symbols from a file\n"
754 " -T file Dump expanded types into file\n"
755 " -p Preserve reference modversions or fail\n"
756 " -w Enable warnings\n"
757 " -q Disable warnings (default)\n"
758 " -h Print this message\n"
759 " -V Print the release version\n"
760 " -R Emit section relative symbol CRCs\n"
761#endif /* __GNU_LIBRARY__ */
762 , stderr);
763}
764
765int main(int argc, char **argv)
766{
767 FILE *dumpfile = NULL, *ref_file = NULL;
768 int o;
769
770#ifdef __GNU_LIBRARY__
771 struct option long_opts[] = {
772 {"symbol-prefix", 1, 0, 's'},
773 {"debug", 0, 0, 'd'},
774 {"warnings", 0, 0, 'w'},
775 {"quiet", 0, 0, 'q'},
776 {"dump", 0, 0, 'D'},
777 {"reference", 1, 0, 'r'},
778 {"dump-types", 1, 0, 'T'},
779 {"preserve", 0, 0, 'p'},
780 {"version", 0, 0, 'V'},
781 {"help", 0, 0, 'h'},
782 {"relative-crc", 0, 0, 'R'},
783 {0, 0, 0, 0}
784 };
785
786 while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
787 &long_opts[0], NULL)) != EOF)
788#else /* __GNU_LIBRARY__ */
789 while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
790#endif /* __GNU_LIBRARY__ */
791 switch (o) {
792 case 's':
793 mod_prefix = optarg;
794 break;
795 case 'd':
796 flag_debug++;
797 break;
798 case 'w':
799 flag_warnings = 1;
800 break;
801 case 'q':
802 flag_warnings = 0;
803 break;
804 case 'V':
805 fputs("genksyms version 2.5.60\n", stderr);
806 break;
807 case 'D':
808 flag_dump_defs = 1;
809 break;
810 case 'r':
811 flag_reference = 1;
812 ref_file = fopen(optarg, "r");
813 if (!ref_file) {
814 perror(optarg);
815 return 1;
816 }
817 break;
818 case 'T':
819 flag_dump_types = 1;
820 dumpfile = fopen(optarg, "w");
821 if (!dumpfile) {
822 perror(optarg);
823 return 1;
824 }
825 break;
826 case 'p':
827 flag_preserve = 1;
828 break;
829 case 'h':
830 genksyms_usage();
831 return 0;
832 case 'R':
833 flag_rel_crcs = 1;
834 break;
835 default:
836 genksyms_usage();
837 return 1;
838 }
839 {
840 extern int yydebug;
841 extern int yy_flex_debug;
842
843 yydebug = (flag_debug > 1);
844 yy_flex_debug = (flag_debug > 2);
845
846 debugfile = stderr;
847 /* setlinebuf(debugfile); */
848 }
849
850 if (flag_reference) {
851 read_reference(ref_file);
852 fclose(ref_file);
853 }
854
855 yyparse();
856
857 if (flag_dump_types && visited_symbols) {
858 while (visited_symbols != (struct symbol *)-1L) {
859 struct symbol *sym = visited_symbols;
860
861 if (sym->is_override)
862 fputs("override ", dumpfile);
863 if (symbol_types[sym->type].n) {
864 putc(symbol_types[sym->type].n, dumpfile);
865 putc('#', dumpfile);
866 }
867 fputs(sym->name, dumpfile);
868 putc(' ', dumpfile);
869 if (sym->is_extern)
870 fputs("extern ", dumpfile);
871 print_list(dumpfile, sym->defn);
872 putc('\n', dumpfile);
873
874 visited_symbols = sym->visited;
875 sym->visited = NULL;
876 }
877 }
878
879 if (flag_debug) {
880 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
881 nsyms, HASH_BUCKETS,
882 (double)nsyms / (double)HASH_BUCKETS);
883 }
884
885 if (dumpfile)
886 fclose(dumpfile);
887
888 return errors != 0;
889}
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}