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
process_enum(const char * name,enum symbol_type type,struct string_list * defn)184 static struct string_list *process_enum(const char *name, enum symbol_type type,
185 struct string_list *defn)
186 {
187 /* The parser adds symbols in the order their declaration completes,
188 * so it is safe to store the value of the previous enum constant in
189 * a static variable.
190 */
191 static int enum_counter;
192 static struct string_list *last_enum_expr;
193
194 if (type == SYM_ENUM_CONST) {
195 if (defn) {
196 free_list(last_enum_expr, NULL);
197 last_enum_expr = copy_list_range(defn, NULL);
198 enum_counter = 1;
199 } else {
200 struct string_list *expr;
201 char buf[20];
202
203 snprintf(buf, sizeof(buf), "%d", enum_counter++);
204 if (last_enum_expr) {
205 expr = copy_list_range(last_enum_expr, NULL);
206 defn = concat_list(mk_node("("),
207 expr,
208 mk_node(")"),
209 mk_node("+"),
210 mk_node(buf), NULL);
211 } else {
212 defn = mk_node(buf);
213 }
214 }
215 } else {
216 free_list(last_enum_expr, NULL);
217 last_enum_expr = NULL;
218 enum_counter = 0;
219 if (!name)
220 /* Anonymous enum definition, nothing more to do */
221 return NULL;
222 }
223
224 return defn;
225 }
226
__add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern,int is_reference)227 static struct symbol *__add_symbol(const char *name, enum symbol_type type,
228 struct string_list *defn, int is_extern,
229 int is_reference)
230 {
231 unsigned long h;
232 struct symbol *sym;
233 enum symbol_status status = STATUS_UNCHANGED;
234
235 if ((type == SYM_ENUM_CONST || type == SYM_ENUM) && !is_reference) {
236 defn = process_enum(name, type, defn);
237 if (defn == NULL)
238 return NULL;
239 }
240
241 h = crc32(name);
242 hash_for_each_possible(symbol_hashtable, sym, hnode, h) {
243 if (map_to_ns(sym->type) != map_to_ns(type) ||
244 strcmp(name, sym->name))
245 continue;
246
247 if (is_reference) {
248 break;
249 } else if (sym->type == type && equal_list(sym->defn, defn)) {
250 if (!sym->is_declared && sym->is_override) {
251 print_location();
252 print_type_name(type, name);
253 fprintf(stderr, " modversion is unchanged\n");
254 }
255 sym->is_declared = 1;
256 } else if (sym->is_declared) {
257 error_with_pos("redefinition of %s", name);
258 } else 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 } else {
265 status = is_unknown_symbol(sym) ?
266 STATUS_DEFINED : STATUS_MODIFIED;
267 break;
268 }
269 free_list(defn, NULL);
270 return sym;
271 }
272
273 if (sym) {
274 hash_del(&sym->hnode);
275
276 free_list(sym->defn, NULL);
277 free(sym->name);
278 free(sym);
279 --nsyms;
280 }
281
282 sym = xmalloc(sizeof(*sym));
283 sym->name = xstrdup(name);
284 sym->type = type;
285 sym->defn = defn;
286 sym->expansion_trail = NULL;
287 sym->visited = NULL;
288 sym->is_extern = is_extern;
289
290 hash_add(symbol_hashtable, &sym->hnode, h);
291
292 sym->is_declared = !is_reference;
293 sym->status = status;
294 sym->is_override = 0;
295
296 if (flag_debug) {
297 if (symbol_types[type].name)
298 fprintf(debugfile, "Defn for %s %s == <",
299 symbol_types[type].name, name);
300 else
301 fprintf(debugfile, "Defn for type%d %s == <",
302 type, name);
303 if (is_extern)
304 fputs("extern ", debugfile);
305 print_list(debugfile, defn);
306 fputs(">\n", debugfile);
307 }
308
309 ++nsyms;
310 return sym;
311 }
312
add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)313 struct symbol *add_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, 0);
317 }
318
add_reference_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)319 static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
320 struct string_list *defn, int is_extern)
321 {
322 return __add_symbol(name, type, defn, is_extern, 1);
323 }
324
325 /*----------------------------------------------------------------------*/
326
free_node(struct string_list * node)327 void free_node(struct string_list *node)
328 {
329 free(node->string);
330 free(node);
331 }
332
free_list(struct string_list * s,struct string_list * e)333 void free_list(struct string_list *s, struct string_list *e)
334 {
335 while (s != e) {
336 struct string_list *next = s->next;
337 free_node(s);
338 s = next;
339 }
340 }
341
mk_node(const char * string)342 static struct string_list *mk_node(const char *string)
343 {
344 struct string_list *newnode;
345
346 newnode = xmalloc(sizeof(*newnode));
347 newnode->string = xstrdup(string);
348 newnode->tag = SYM_NORMAL;
349 newnode->next = NULL;
350
351 return newnode;
352 }
353
concat_list(struct string_list * start,...)354 static struct string_list *concat_list(struct string_list *start, ...)
355 {
356 va_list ap;
357 struct string_list *n, *n2;
358
359 if (!start)
360 return NULL;
361 for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
362 for (n2 = n; n2->next; n2 = n2->next)
363 ;
364 n2->next = start;
365 start = n;
366 }
367 va_end(ap);
368 return start;
369 }
370
copy_node(struct string_list * node)371 struct string_list *copy_node(struct string_list *node)
372 {
373 struct string_list *newnode;
374
375 newnode = xmalloc(sizeof(*newnode));
376 newnode->string = xstrdup(node->string);
377 newnode->tag = node->tag;
378
379 return newnode;
380 }
381
copy_list_range(struct string_list * start,struct string_list * end)382 struct string_list *copy_list_range(struct string_list *start,
383 struct string_list *end)
384 {
385 struct string_list *res, *n;
386
387 if (start == end)
388 return NULL;
389 n = res = copy_node(start);
390 for (start = start->next; start != end; start = start->next) {
391 n->next = copy_node(start);
392 n = n->next;
393 }
394 n->next = NULL;
395 return res;
396 }
397
equal_list(struct string_list * a,struct string_list * b)398 static int equal_list(struct string_list *a, struct string_list *b)
399 {
400 while (a && b) {
401 if (a->tag != b->tag || strcmp(a->string, b->string))
402 return 0;
403 a = a->next;
404 b = b->next;
405 }
406
407 return !a && !b;
408 }
409
410 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
411
read_node(FILE * f)412 static struct string_list *read_node(FILE *f)
413 {
414 char buffer[256];
415 struct string_list node = {
416 .string = buffer,
417 .tag = SYM_NORMAL };
418 int c, in_string = 0;
419
420 while ((c = fgetc(f)) != EOF) {
421 if (!in_string && c == ' ') {
422 if (node.string == buffer)
423 continue;
424 break;
425 } else if (c == '"') {
426 in_string = !in_string;
427 } else if (c == '\n') {
428 if (node.string == buffer)
429 return NULL;
430 ungetc(c, f);
431 break;
432 }
433 if (node.string >= buffer + sizeof(buffer) - 1) {
434 fprintf(stderr, "Token too long\n");
435 exit(1);
436 }
437 *node.string++ = c;
438 }
439 if (node.string == buffer)
440 return NULL;
441 *node.string = 0;
442 node.string = buffer;
443
444 if (node.string[1] == '#') {
445 size_t n;
446
447 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
448 if (node.string[0] == symbol_types[n].n) {
449 node.tag = n;
450 node.string += 2;
451 return copy_node(&node);
452 }
453 }
454 fprintf(stderr, "Unknown type %c\n", node.string[0]);
455 exit(1);
456 }
457 return copy_node(&node);
458 }
459
read_reference(FILE * f)460 static void read_reference(FILE *f)
461 {
462 while (!feof(f)) {
463 struct string_list *defn = NULL;
464 struct string_list *sym, *def;
465 int is_extern = 0, is_override = 0;
466 struct symbol *subsym;
467
468 sym = read_node(f);
469 if (sym && sym->tag == SYM_NORMAL &&
470 !strcmp(sym->string, "override")) {
471 is_override = 1;
472 free_node(sym);
473 sym = read_node(f);
474 }
475 if (!sym)
476 continue;
477 def = read_node(f);
478 if (def && def->tag == SYM_NORMAL &&
479 !strcmp(def->string, "extern")) {
480 is_extern = 1;
481 free_node(def);
482 def = read_node(f);
483 }
484 while (def) {
485 def->next = defn;
486 defn = def;
487 def = read_node(f);
488 }
489 subsym = add_reference_symbol(sym->string, sym->tag,
490 defn, is_extern);
491 subsym->is_override = is_override;
492 free_node(sym);
493 }
494 }
495
print_node(FILE * f,struct string_list * list)496 static void print_node(FILE * f, struct string_list *list)
497 {
498 if (symbol_types[list->tag].n) {
499 putc(symbol_types[list->tag].n, f);
500 putc('#', f);
501 }
502 fputs(list->string, f);
503 }
504
print_list(FILE * f,struct string_list * list)505 static void print_list(FILE * f, struct string_list *list)
506 {
507 struct string_list **e, **b;
508 struct string_list *tmp, **tmp2;
509 int elem = 1;
510
511 if (list == NULL) {
512 fputs("(nil)", f);
513 return;
514 }
515
516 tmp = list;
517 while ((tmp = tmp->next) != NULL)
518 elem++;
519
520 b = alloca(elem * sizeof(*e));
521 e = b + elem;
522 tmp2 = e - 1;
523
524 (*tmp2--) = list;
525 while ((list = list->next) != NULL)
526 *(tmp2--) = list;
527
528 while (b != e) {
529 print_node(f, *b++);
530 putc(' ', f);
531 }
532 }
533
expand_and_crc_sym(struct symbol * sym,uint32_t crc)534 static uint32_t expand_and_crc_sym(struct symbol *sym, uint32_t crc)
535 {
536 struct string_list *list = sym->defn;
537 struct string_list **e, **b;
538 struct string_list *tmp, **tmp2;
539 int elem = 1;
540
541 if (!list)
542 return crc;
543
544 tmp = list;
545 while ((tmp = tmp->next) != NULL)
546 elem++;
547
548 b = alloca(elem * sizeof(*e));
549 e = b + elem;
550 tmp2 = e - 1;
551
552 *(tmp2--) = list;
553 while ((list = list->next) != NULL)
554 *(tmp2--) = list;
555
556 while (b != e) {
557 struct string_list *cur;
558 struct symbol *subsym;
559
560 cur = *(b++);
561 switch (cur->tag) {
562 case SYM_NORMAL:
563 if (flag_dump_defs)
564 fprintf(debugfile, "%s ", cur->string);
565 crc = partial_crc32(cur->string, crc);
566 crc = partial_crc32_one(' ', crc);
567 break;
568
569 case SYM_ENUM_CONST:
570 case SYM_TYPEDEF:
571 subsym = find_symbol(cur->string, cur->tag, 0);
572 /* FIXME: Bad reference files can segfault here. */
573 if (subsym->expansion_trail) {
574 if (flag_dump_defs)
575 fprintf(debugfile, "%s ", cur->string);
576 crc = partial_crc32(cur->string, crc);
577 crc = partial_crc32_one(' ', crc);
578 } else {
579 subsym->expansion_trail = expansion_trail;
580 expansion_trail = subsym;
581 crc = expand_and_crc_sym(subsym, crc);
582 }
583 break;
584
585 case SYM_STRUCT:
586 case SYM_UNION:
587 case SYM_ENUM:
588 subsym = find_symbol(cur->string, cur->tag, 0);
589 if (!subsym) {
590 struct string_list *n;
591
592 error_with_pos("expand undefined %s %s",
593 symbol_types[cur->tag].name,
594 cur->string);
595 n = concat_list(mk_node
596 (symbol_types[cur->tag].name),
597 mk_node(cur->string),
598 mk_node("{"),
599 mk_node("UNKNOWN"),
600 mk_node("}"), NULL);
601 subsym =
602 add_symbol(cur->string, cur->tag, n, 0);
603 }
604 if (subsym->expansion_trail) {
605 if (flag_dump_defs) {
606 fprintf(debugfile, "%s %s ",
607 symbol_types[cur->tag].name,
608 cur->string);
609 }
610
611 crc = partial_crc32(symbol_types[cur->tag].name,
612 crc);
613 crc = partial_crc32_one(' ', crc);
614 crc = partial_crc32(cur->string, crc);
615 crc = partial_crc32_one(' ', crc);
616 } else {
617 subsym->expansion_trail = expansion_trail;
618 expansion_trail = subsym;
619 crc = expand_and_crc_sym(subsym, crc);
620 }
621 break;
622 }
623 }
624
625 {
626 static struct symbol **end = &visited_symbols;
627
628 if (!sym->visited) {
629 *end = sym;
630 end = &sym->visited;
631 sym->visited = (struct symbol *)-1L;
632 }
633 }
634
635 return crc;
636 }
637
export_symbol(const char * name)638 void export_symbol(const char *name)
639 {
640 struct symbol *sym;
641 uint32_t crc;
642 int has_changed = 0;
643
644 sym = find_symbol(name, SYM_NORMAL, 0);
645 if (!sym) {
646 error_with_pos("export undefined symbol %s", name);
647 return;
648 }
649
650 if (flag_dump_defs)
651 fprintf(debugfile, "Export %s == <", name);
652
653 expansion_trail = (struct symbol *)-1L;
654
655 sym->expansion_trail = expansion_trail;
656 expansion_trail = sym;
657 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
658
659 sym = expansion_trail;
660 while (sym != (struct symbol *)-1L) {
661 struct symbol *n = sym->expansion_trail;
662
663 if (sym->status != STATUS_UNCHANGED) {
664 if (!has_changed) {
665 print_location();
666 fprintf(stderr,
667 "%s: %s: modversion changed because of changes in ",
668 flag_preserve ? "error" : "warning",
669 name);
670 } else {
671 fprintf(stderr, ", ");
672 }
673 print_type_name(sym->type, sym->name);
674 if (sym->status == STATUS_DEFINED)
675 fprintf(stderr, " (became defined)");
676 has_changed = 1;
677 if (flag_preserve)
678 errors++;
679 }
680 sym->expansion_trail = 0;
681 sym = n;
682 }
683 if (has_changed)
684 fprintf(stderr, "\n");
685
686 if (flag_dump_defs)
687 fputs(">\n", debugfile);
688
689 printf("#SYMVER %s 0x%08lx\n", name, (unsigned long)crc);
690 }
691
692 /*----------------------------------------------------------------------*/
693
print_location(void)694 static void print_location(void)
695 {
696 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
697 }
698
print_type_name(enum symbol_type type,const char * name)699 static void print_type_name(enum symbol_type type, const char *name)
700 {
701 if (symbol_types[type].name)
702 fprintf(stderr, "%s %s", symbol_types[type].name, name);
703 else
704 fprintf(stderr, "%s", name);
705 }
706
error_with_pos(const char * fmt,...)707 void error_with_pos(const char *fmt, ...)
708 {
709 va_list args;
710
711 if (flag_warnings) {
712 print_location();
713
714 va_start(args, fmt);
715 vfprintf(stderr, fmt, args);
716 va_end(args);
717 putc('\n', stderr);
718
719 errors++;
720 }
721 }
722
genksyms_usage(void)723 static void genksyms_usage(void)
724 {
725 fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
726 " -d, --debug Increment the debug level (repeatable)\n"
727 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
728 " -r, --reference file Read reference symbols from a file\n"
729 " -T, --dump-types file Dump expanded types into file\n"
730 " -p, --preserve Preserve reference modversions or fail\n"
731 " -w, --warnings Enable warnings\n"
732 " -q, --quiet Disable warnings (default)\n"
733 " -h, --help Print this message\n"
734 " -V, --version Print the release version\n"
735 , stderr);
736 }
737
main(int argc,char ** argv)738 int main(int argc, char **argv)
739 {
740 FILE *dumpfile = NULL, *ref_file = NULL;
741 int o;
742
743 struct option long_opts[] = {
744 {"debug", 0, 0, 'd'},
745 {"warnings", 0, 0, 'w'},
746 {"quiet", 0, 0, 'q'},
747 {"dump", 0, 0, 'D'},
748 {"reference", 1, 0, 'r'},
749 {"dump-types", 1, 0, 'T'},
750 {"preserve", 0, 0, 'p'},
751 {"version", 0, 0, 'V'},
752 {"help", 0, 0, 'h'},
753 {0, 0, 0, 0}
754 };
755
756 while ((o = getopt_long(argc, argv, "dwqVDr:T:ph",
757 &long_opts[0], NULL)) != EOF)
758 switch (o) {
759 case 'd':
760 flag_debug++;
761 break;
762 case 'w':
763 flag_warnings = 1;
764 break;
765 case 'q':
766 flag_warnings = 0;
767 break;
768 case 'V':
769 fputs("genksyms version 2.5.60\n", stderr);
770 break;
771 case 'D':
772 flag_dump_defs = 1;
773 break;
774 case 'r':
775 flag_reference = 1;
776 ref_file = fopen(optarg, "r");
777 if (!ref_file) {
778 perror(optarg);
779 return 1;
780 }
781 break;
782 case 'T':
783 flag_dump_types = 1;
784 dumpfile = fopen(optarg, "w");
785 if (!dumpfile) {
786 perror(optarg);
787 return 1;
788 }
789 break;
790 case 'p':
791 flag_preserve = 1;
792 break;
793 case 'h':
794 genksyms_usage();
795 return 0;
796 default:
797 genksyms_usage();
798 return 1;
799 }
800 {
801 extern int yydebug;
802 extern int yy_flex_debug;
803
804 yydebug = (flag_debug > 1);
805 yy_flex_debug = (flag_debug > 2);
806
807 debugfile = stderr;
808 /* setlinebuf(debugfile); */
809 }
810
811 if (flag_reference) {
812 read_reference(ref_file);
813 fclose(ref_file);
814 }
815
816 yyparse();
817
818 if (flag_dump_types && visited_symbols) {
819 while (visited_symbols != (struct symbol *)-1L) {
820 struct symbol *sym = visited_symbols;
821
822 if (sym->is_override)
823 fputs("override ", dumpfile);
824 if (symbol_types[sym->type].n) {
825 putc(symbol_types[sym->type].n, dumpfile);
826 putc('#', dumpfile);
827 }
828 fputs(sym->name, dumpfile);
829 putc(' ', dumpfile);
830 if (sym->is_extern)
831 fputs("extern ", dumpfile);
832 print_list(dumpfile, sym->defn);
833 putc('\n', dumpfile);
834
835 visited_symbols = sym->visited;
836 sym->visited = NULL;
837 }
838 }
839
840 if (flag_debug) {
841 fprintf(debugfile, "Hash table occupancy %d/%zd = %g\n",
842 nsyms, HASH_SIZE(symbol_hashtable),
843 (double)nsyms / HASH_SIZE(symbol_hashtable));
844 }
845
846 if (dumpfile)
847 fclose(dumpfile);
848
849 return errors != 0;
850 }
851