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