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
28 static struct symbol *symtab[HASH_BUCKETS];
29 static FILE *debugfile;
30
31 int cur_line = 1;
32 char *cur_filename;
33 int in_source_file;
34
35 static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
36 flag_preserve, flag_warnings;
37
38 static int errors;
39 static int nsyms;
40
41 static struct symbol *expansion_trail;
42 static struct symbol *visited_symbols;
43
44 static 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
56 static int equal_list(struct string_list *a, struct string_list *b);
57 static void print_list(FILE * f, struct string_list *list);
58 static struct string_list *concat_list(struct string_list *start, ...);
59 static struct string_list *mk_node(const char *string);
60 static void print_location(void);
61 static void print_type_name(enum symbol_type type, const char *name);
62
63 /*----------------------------------------------------------------------*/
64
65 static 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
partial_crc32_one(unsigned char c,unsigned long crc)120 static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
121 {
122 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
123 }
124
partial_crc32(const char * s,unsigned long crc)125 static 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
crc32(const char * s)132 static unsigned long crc32(const char *s)
133 {
134 return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
135 }
136
137 /*----------------------------------------------------------------------*/
138
map_to_ns(enum symbol_type t)139 static 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
find_symbol(const char * name,enum symbol_type ns,int exact)154 struct 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
is_unknown_symbol(struct symbol * sym)170 static 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
__add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern,int is_reference)185 static 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 free_list(defn, NULL);
245 return sym;
246 } else if (!sym->is_declared) {
247 if (sym->is_override && flag_preserve) {
248 print_location();
249 fprintf(stderr, "ignoring ");
250 print_type_name(type, name);
251 fprintf(stderr, " modversion change\n");
252 sym->is_declared = 1;
253 free_list(defn, NULL);
254 return sym;
255 } else {
256 status = is_unknown_symbol(sym) ?
257 STATUS_DEFINED : STATUS_MODIFIED;
258 }
259 } else {
260 error_with_pos("redefinition of %s", name);
261 free_list(defn, NULL);
262 return sym;
263 }
264 break;
265 }
266 }
267
268 if (sym) {
269 struct symbol **psym;
270
271 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
272 if (*psym == sym) {
273 *psym = sym->hash_next;
274 break;
275 }
276 }
277
278 free_list(sym->defn, NULL);
279 free(sym->name);
280 free(sym);
281 --nsyms;
282 }
283
284 sym = xmalloc(sizeof(*sym));
285 sym->name = xstrdup(name);
286 sym->type = type;
287 sym->defn = defn;
288 sym->expansion_trail = NULL;
289 sym->visited = NULL;
290 sym->is_extern = is_extern;
291
292 sym->hash_next = symtab[h];
293 symtab[h] = sym;
294
295 sym->is_declared = !is_reference;
296 sym->status = status;
297 sym->is_override = 0;
298
299 if (flag_debug) {
300 if (symbol_types[type].name)
301 fprintf(debugfile, "Defn for %s %s == <",
302 symbol_types[type].name, name);
303 else
304 fprintf(debugfile, "Defn for type%d %s == <",
305 type, name);
306 if (is_extern)
307 fputs("extern ", debugfile);
308 print_list(debugfile, defn);
309 fputs(">\n", debugfile);
310 }
311
312 ++nsyms;
313 return sym;
314 }
315
add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)316 struct symbol *add_symbol(const char *name, enum symbol_type type,
317 struct string_list *defn, int is_extern)
318 {
319 return __add_symbol(name, type, defn, is_extern, 0);
320 }
321
add_reference_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)322 static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
323 struct string_list *defn, int is_extern)
324 {
325 return __add_symbol(name, type, defn, is_extern, 1);
326 }
327
328 /*----------------------------------------------------------------------*/
329
free_node(struct string_list * node)330 void free_node(struct string_list *node)
331 {
332 free(node->string);
333 free(node);
334 }
335
free_list(struct string_list * s,struct string_list * e)336 void free_list(struct string_list *s, struct string_list *e)
337 {
338 while (s != e) {
339 struct string_list *next = s->next;
340 free_node(s);
341 s = next;
342 }
343 }
344
mk_node(const char * string)345 static struct string_list *mk_node(const char *string)
346 {
347 struct string_list *newnode;
348
349 newnode = xmalloc(sizeof(*newnode));
350 newnode->string = xstrdup(string);
351 newnode->tag = SYM_NORMAL;
352 newnode->next = NULL;
353
354 return newnode;
355 }
356
concat_list(struct string_list * start,...)357 static struct string_list *concat_list(struct string_list *start, ...)
358 {
359 va_list ap;
360 struct string_list *n, *n2;
361
362 if (!start)
363 return NULL;
364 for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
365 for (n2 = n; n2->next; n2 = n2->next)
366 ;
367 n2->next = start;
368 start = n;
369 }
370 va_end(ap);
371 return start;
372 }
373
copy_node(struct string_list * node)374 struct string_list *copy_node(struct string_list *node)
375 {
376 struct string_list *newnode;
377
378 newnode = xmalloc(sizeof(*newnode));
379 newnode->string = xstrdup(node->string);
380 newnode->tag = node->tag;
381
382 return newnode;
383 }
384
copy_list_range(struct string_list * start,struct string_list * end)385 struct string_list *copy_list_range(struct string_list *start,
386 struct string_list *end)
387 {
388 struct string_list *res, *n;
389
390 if (start == end)
391 return NULL;
392 n = res = copy_node(start);
393 for (start = start->next; start != end; start = start->next) {
394 n->next = copy_node(start);
395 n = n->next;
396 }
397 n->next = NULL;
398 return res;
399 }
400
equal_list(struct string_list * a,struct string_list * b)401 static int equal_list(struct string_list *a, struct string_list *b)
402 {
403 while (a && b) {
404 if (a->tag != b->tag || strcmp(a->string, b->string))
405 return 0;
406 a = a->next;
407 b = b->next;
408 }
409
410 return !a && !b;
411 }
412
413 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
414
read_node(FILE * f)415 static struct string_list *read_node(FILE *f)
416 {
417 char buffer[256];
418 struct string_list node = {
419 .string = buffer,
420 .tag = SYM_NORMAL };
421 int c, in_string = 0;
422
423 while ((c = fgetc(f)) != EOF) {
424 if (!in_string && c == ' ') {
425 if (node.string == buffer)
426 continue;
427 break;
428 } else if (c == '"') {
429 in_string = !in_string;
430 } else if (c == '\n') {
431 if (node.string == buffer)
432 return NULL;
433 ungetc(c, f);
434 break;
435 }
436 if (node.string >= buffer + sizeof(buffer) - 1) {
437 fprintf(stderr, "Token too long\n");
438 exit(1);
439 }
440 *node.string++ = c;
441 }
442 if (node.string == buffer)
443 return NULL;
444 *node.string = 0;
445 node.string = buffer;
446
447 if (node.string[1] == '#') {
448 size_t n;
449
450 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
451 if (node.string[0] == symbol_types[n].n) {
452 node.tag = n;
453 node.string += 2;
454 return copy_node(&node);
455 }
456 }
457 fprintf(stderr, "Unknown type %c\n", node.string[0]);
458 exit(1);
459 }
460 return copy_node(&node);
461 }
462
read_reference(FILE * f)463 static void read_reference(FILE *f)
464 {
465 while (!feof(f)) {
466 struct string_list *defn = NULL;
467 struct string_list *sym, *def;
468 int is_extern = 0, is_override = 0;
469 struct symbol *subsym;
470
471 sym = read_node(f);
472 if (sym && sym->tag == SYM_NORMAL &&
473 !strcmp(sym->string, "override")) {
474 is_override = 1;
475 free_node(sym);
476 sym = read_node(f);
477 }
478 if (!sym)
479 continue;
480 def = read_node(f);
481 if (def && def->tag == SYM_NORMAL &&
482 !strcmp(def->string, "extern")) {
483 is_extern = 1;
484 free_node(def);
485 def = read_node(f);
486 }
487 while (def) {
488 def->next = defn;
489 defn = def;
490 def = read_node(f);
491 }
492 subsym = add_reference_symbol(sym->string, sym->tag,
493 defn, is_extern);
494 subsym->is_override = is_override;
495 free_node(sym);
496 }
497 }
498
print_node(FILE * f,struct string_list * list)499 static void print_node(FILE * f, struct string_list *list)
500 {
501 if (symbol_types[list->tag].n) {
502 putc(symbol_types[list->tag].n, f);
503 putc('#', f);
504 }
505 fputs(list->string, f);
506 }
507
print_list(FILE * f,struct string_list * list)508 static void print_list(FILE * f, struct string_list *list)
509 {
510 struct string_list **e, **b;
511 struct string_list *tmp, **tmp2;
512 int elem = 1;
513
514 if (list == NULL) {
515 fputs("(nil)", f);
516 return;
517 }
518
519 tmp = list;
520 while ((tmp = tmp->next) != NULL)
521 elem++;
522
523 b = alloca(elem * sizeof(*e));
524 e = b + elem;
525 tmp2 = e - 1;
526
527 (*tmp2--) = list;
528 while ((list = list->next) != NULL)
529 *(tmp2--) = list;
530
531 while (b != e) {
532 print_node(f, *b++);
533 putc(' ', f);
534 }
535 }
536
expand_and_crc_sym(struct symbol * sym,unsigned long crc)537 static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
538 {
539 struct string_list *list = sym->defn;
540 struct string_list **e, **b;
541 struct string_list *tmp, **tmp2;
542 int elem = 1;
543
544 if (!list)
545 return crc;
546
547 tmp = list;
548 while ((tmp = tmp->next) != NULL)
549 elem++;
550
551 b = alloca(elem * sizeof(*e));
552 e = b + elem;
553 tmp2 = e - 1;
554
555 *(tmp2--) = list;
556 while ((list = list->next) != NULL)
557 *(tmp2--) = list;
558
559 while (b != e) {
560 struct string_list *cur;
561 struct symbol *subsym;
562
563 cur = *(b++);
564 switch (cur->tag) {
565 case SYM_NORMAL:
566 if (flag_dump_defs)
567 fprintf(debugfile, "%s ", cur->string);
568 crc = partial_crc32(cur->string, crc);
569 crc = partial_crc32_one(' ', crc);
570 break;
571
572 case SYM_ENUM_CONST:
573 case SYM_TYPEDEF:
574 subsym = find_symbol(cur->string, cur->tag, 0);
575 /* FIXME: Bad reference files can segfault here. */
576 if (subsym->expansion_trail) {
577 if (flag_dump_defs)
578 fprintf(debugfile, "%s ", cur->string);
579 crc = partial_crc32(cur->string, crc);
580 crc = partial_crc32_one(' ', crc);
581 } else {
582 subsym->expansion_trail = expansion_trail;
583 expansion_trail = subsym;
584 crc = expand_and_crc_sym(subsym, crc);
585 }
586 break;
587
588 case SYM_STRUCT:
589 case SYM_UNION:
590 case SYM_ENUM:
591 subsym = find_symbol(cur->string, cur->tag, 0);
592 if (!subsym) {
593 struct string_list *n;
594
595 error_with_pos("expand undefined %s %s",
596 symbol_types[cur->tag].name,
597 cur->string);
598 n = concat_list(mk_node
599 (symbol_types[cur->tag].name),
600 mk_node(cur->string),
601 mk_node("{"),
602 mk_node("UNKNOWN"),
603 mk_node("}"), NULL);
604 subsym =
605 add_symbol(cur->string, cur->tag, n, 0);
606 }
607 if (subsym->expansion_trail) {
608 if (flag_dump_defs) {
609 fprintf(debugfile, "%s %s ",
610 symbol_types[cur->tag].name,
611 cur->string);
612 }
613
614 crc = partial_crc32(symbol_types[cur->tag].name,
615 crc);
616 crc = partial_crc32_one(' ', crc);
617 crc = partial_crc32(cur->string, crc);
618 crc = partial_crc32_one(' ', crc);
619 } else {
620 subsym->expansion_trail = expansion_trail;
621 expansion_trail = subsym;
622 crc = expand_and_crc_sym(subsym, crc);
623 }
624 break;
625 }
626 }
627
628 {
629 static struct symbol **end = &visited_symbols;
630
631 if (!sym->visited) {
632 *end = sym;
633 end = &sym->visited;
634 sym->visited = (struct symbol *)-1L;
635 }
636 }
637
638 return crc;
639 }
640
export_symbol(const char * name)641 void export_symbol(const char *name)
642 {
643 struct symbol *sym;
644
645 sym = find_symbol(name, SYM_NORMAL, 0);
646 if (!sym)
647 error_with_pos("export undefined symbol %s", name);
648 else {
649 unsigned long crc;
650 int has_changed = 0;
651
652 if (flag_dump_defs)
653 fprintf(debugfile, "Export %s == <", name);
654
655 expansion_trail = (struct symbol *)-1L;
656
657 sym->expansion_trail = expansion_trail;
658 expansion_trail = sym;
659 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
660
661 sym = expansion_trail;
662 while (sym != (struct symbol *)-1L) {
663 struct symbol *n = sym->expansion_trail;
664
665 if (sym->status != STATUS_UNCHANGED) {
666 if (!has_changed) {
667 print_location();
668 fprintf(stderr, "%s: %s: modversion "
669 "changed because of changes "
670 "in ", flag_preserve ? "error" :
671 "warning", name);
672 } else
673 fprintf(stderr, ", ");
674 print_type_name(sym->type, sym->name);
675 if (sym->status == STATUS_DEFINED)
676 fprintf(stderr, " (became defined)");
677 has_changed = 1;
678 if (flag_preserve)
679 errors++;
680 }
681 sym->expansion_trail = 0;
682 sym = n;
683 }
684 if (has_changed)
685 fprintf(stderr, "\n");
686
687 if (flag_dump_defs)
688 fputs(">\n", debugfile);
689
690 printf("#SYMVER %s 0x%08lx\n", name, crc);
691 }
692 }
693
694 /*----------------------------------------------------------------------*/
695
print_location(void)696 static void print_location(void)
697 {
698 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
699 }
700
print_type_name(enum symbol_type type,const char * name)701 static void print_type_name(enum symbol_type type, const char *name)
702 {
703 if (symbol_types[type].name)
704 fprintf(stderr, "%s %s", symbol_types[type].name, name);
705 else
706 fprintf(stderr, "%s", name);
707 }
708
error_with_pos(const char * fmt,...)709 void error_with_pos(const char *fmt, ...)
710 {
711 va_list args;
712
713 if (flag_warnings) {
714 print_location();
715
716 va_start(args, fmt);
717 vfprintf(stderr, fmt, args);
718 va_end(args);
719 putc('\n', stderr);
720
721 errors++;
722 }
723 }
724
genksyms_usage(void)725 static void genksyms_usage(void)
726 {
727 fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
728 #ifdef __GNU_LIBRARY__
729 " -s, --symbol-prefix Select symbol prefix\n"
730 " -d, --debug Increment the debug level (repeatable)\n"
731 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
732 " -r, --reference file Read reference symbols from a file\n"
733 " -T, --dump-types file Dump expanded types into file\n"
734 " -p, --preserve Preserve reference modversions or fail\n"
735 " -w, --warnings Enable warnings\n"
736 " -q, --quiet Disable warnings (default)\n"
737 " -h, --help Print this message\n"
738 " -V, --version Print the release version\n"
739 #else /* __GNU_LIBRARY__ */
740 " -s Select symbol prefix\n"
741 " -d Increment the debug level (repeatable)\n"
742 " -D Dump expanded symbol defs (for debugging only)\n"
743 " -r file Read reference symbols from a file\n"
744 " -T file Dump expanded types into file\n"
745 " -p Preserve reference modversions or fail\n"
746 " -w Enable warnings\n"
747 " -q Disable warnings (default)\n"
748 " -h Print this message\n"
749 " -V Print the release version\n"
750 #endif /* __GNU_LIBRARY__ */
751 , stderr);
752 }
753
main(int argc,char ** argv)754 int main(int argc, char **argv)
755 {
756 FILE *dumpfile = NULL, *ref_file = NULL;
757 int o;
758
759 #ifdef __GNU_LIBRARY__
760 struct option long_opts[] = {
761 {"debug", 0, 0, 'd'},
762 {"warnings", 0, 0, 'w'},
763 {"quiet", 0, 0, 'q'},
764 {"dump", 0, 0, 'D'},
765 {"reference", 1, 0, 'r'},
766 {"dump-types", 1, 0, 'T'},
767 {"preserve", 0, 0, 'p'},
768 {"version", 0, 0, 'V'},
769 {"help", 0, 0, 'h'},
770 {0, 0, 0, 0}
771 };
772
773 while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
774 &long_opts[0], NULL)) != EOF)
775 #else /* __GNU_LIBRARY__ */
776 while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != 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 default:
817 genksyms_usage();
818 return 1;
819 }
820 {
821 extern int yydebug;
822 extern int yy_flex_debug;
823
824 yydebug = (flag_debug > 1);
825 yy_flex_debug = (flag_debug > 2);
826
827 debugfile = stderr;
828 /* setlinebuf(debugfile); */
829 }
830
831 if (flag_reference) {
832 read_reference(ref_file);
833 fclose(ref_file);
834 }
835
836 yyparse();
837
838 if (flag_dump_types && visited_symbols) {
839 while (visited_symbols != (struct symbol *)-1L) {
840 struct symbol *sym = visited_symbols;
841
842 if (sym->is_override)
843 fputs("override ", dumpfile);
844 if (symbol_types[sym->type].n) {
845 putc(symbol_types[sym->type].n, dumpfile);
846 putc('#', dumpfile);
847 }
848 fputs(sym->name, dumpfile);
849 putc(' ', dumpfile);
850 if (sym->is_extern)
851 fputs("extern ", dumpfile);
852 print_list(dumpfile, sym->defn);
853 putc('\n', dumpfile);
854
855 visited_symbols = sym->visited;
856 sym->visited = NULL;
857 }
858 }
859
860 if (flag_debug) {
861 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
862 nsyms, HASH_BUCKETS,
863 (double)nsyms / (double)HASH_BUCKETS);
864 }
865
866 if (dumpfile)
867 fclose(dumpfile);
868
869 return errors != 0;
870 }
871