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
26 static struct symbol *symtab[HASH_BUCKETS];
27 static FILE *debugfile;
28
29 int cur_line = 1;
30 char *cur_filename;
31 int in_source_file;
32
33 static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
34 flag_preserve, flag_warnings;
35
36 static int errors;
37 static int nsyms;
38
39 static struct symbol *expansion_trail;
40 static struct symbol *visited_symbols;
41
42 static 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
54 static int equal_list(struct string_list *a, struct string_list *b);
55 static void print_list(FILE * f, struct string_list *list);
56 static struct string_list *concat_list(struct string_list *start, ...);
57 static struct string_list *mk_node(const char *string);
58 static void print_location(void);
59 static void print_type_name(enum symbol_type type, const char *name);
60
61 /*----------------------------------------------------------------------*/
62
63 static 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
partial_crc32_one(unsigned char c,unsigned long crc)118 static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
119 {
120 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
121 }
122
partial_crc32(const char * s,unsigned long crc)123 static 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
crc32(const char * s)130 static unsigned long crc32(const char *s)
131 {
132 return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
133 }
134
135 /*----------------------------------------------------------------------*/
136
map_to_ns(enum symbol_type t)137 static 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
find_symbol(const char * name,enum symbol_type ns,int exact)152 struct 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
is_unknown_symbol(struct symbol * sym)168 static 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
__add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern,int is_reference)183 static 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 free_list(defn, NULL);
243 return sym;
244 } else if (!sym->is_declared) {
245 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 free_list(defn, NULL);
252 return sym;
253 } else {
254 status = is_unknown_symbol(sym) ?
255 STATUS_DEFINED : STATUS_MODIFIED;
256 }
257 } else {
258 error_with_pos("redefinition of %s", name);
259 free_list(defn, NULL);
260 return sym;
261 }
262 break;
263 }
264 }
265
266 if (sym) {
267 struct symbol **psym;
268
269 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
270 if (*psym == sym) {
271 *psym = sym->hash_next;
272 break;
273 }
274 }
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 sym->hash_next = symtab[h];
291 symtab[h] = sym;
292
293 sym->is_declared = !is_reference;
294 sym->status = status;
295 sym->is_override = 0;
296
297 if (flag_debug) {
298 if (symbol_types[type].name)
299 fprintf(debugfile, "Defn for %s %s == <",
300 symbol_types[type].name, name);
301 else
302 fprintf(debugfile, "Defn for type%d %s == <",
303 type, name);
304 if (is_extern)
305 fputs("extern ", debugfile);
306 print_list(debugfile, defn);
307 fputs(">\n", debugfile);
308 }
309
310 ++nsyms;
311 return sym;
312 }
313
add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)314 struct symbol *add_symbol(const char *name, enum symbol_type type,
315 struct string_list *defn, int is_extern)
316 {
317 return __add_symbol(name, type, defn, is_extern, 0);
318 }
319
add_reference_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)320 static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
321 struct string_list *defn, int is_extern)
322 {
323 return __add_symbol(name, type, defn, is_extern, 1);
324 }
325
326 /*----------------------------------------------------------------------*/
327
free_node(struct string_list * node)328 void free_node(struct string_list *node)
329 {
330 free(node->string);
331 free(node);
332 }
333
free_list(struct string_list * s,struct string_list * e)334 void free_list(struct string_list *s, struct string_list *e)
335 {
336 while (s != e) {
337 struct string_list *next = s->next;
338 free_node(s);
339 s = next;
340 }
341 }
342
mk_node(const char * string)343 static struct string_list *mk_node(const char *string)
344 {
345 struct string_list *newnode;
346
347 newnode = xmalloc(sizeof(*newnode));
348 newnode->string = xstrdup(string);
349 newnode->tag = SYM_NORMAL;
350 newnode->next = NULL;
351
352 return newnode;
353 }
354
concat_list(struct string_list * start,...)355 static struct string_list *concat_list(struct string_list *start, ...)
356 {
357 va_list ap;
358 struct string_list *n, *n2;
359
360 if (!start)
361 return NULL;
362 for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
363 for (n2 = n; n2->next; n2 = n2->next)
364 ;
365 n2->next = start;
366 start = n;
367 }
368 va_end(ap);
369 return start;
370 }
371
copy_node(struct string_list * node)372 struct string_list *copy_node(struct string_list *node)
373 {
374 struct string_list *newnode;
375
376 newnode = xmalloc(sizeof(*newnode));
377 newnode->string = xstrdup(node->string);
378 newnode->tag = node->tag;
379
380 return newnode;
381 }
382
copy_list_range(struct string_list * start,struct string_list * end)383 struct string_list *copy_list_range(struct string_list *start,
384 struct string_list *end)
385 {
386 struct string_list *res, *n;
387
388 if (start == end)
389 return NULL;
390 n = res = copy_node(start);
391 for (start = start->next; start != end; start = start->next) {
392 n->next = copy_node(start);
393 n = n->next;
394 }
395 n->next = NULL;
396 return res;
397 }
398
equal_list(struct string_list * a,struct string_list * b)399 static int equal_list(struct string_list *a, struct string_list *b)
400 {
401 while (a && b) {
402 if (a->tag != b->tag || strcmp(a->string, b->string))
403 return 0;
404 a = a->next;
405 b = b->next;
406 }
407
408 return !a && !b;
409 }
410
411 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
412
read_node(FILE * f)413 static struct string_list *read_node(FILE *f)
414 {
415 char buffer[256];
416 struct string_list node = {
417 .string = buffer,
418 .tag = SYM_NORMAL };
419 int c, in_string = 0;
420
421 while ((c = fgetc(f)) != EOF) {
422 if (!in_string && c == ' ') {
423 if (node.string == buffer)
424 continue;
425 break;
426 } else if (c == '"') {
427 in_string = !in_string;
428 } else if (c == '\n') {
429 if (node.string == buffer)
430 return NULL;
431 ungetc(c, f);
432 break;
433 }
434 if (node.string >= buffer + sizeof(buffer) - 1) {
435 fprintf(stderr, "Token too long\n");
436 exit(1);
437 }
438 *node.string++ = c;
439 }
440 if (node.string == buffer)
441 return NULL;
442 *node.string = 0;
443 node.string = buffer;
444
445 if (node.string[1] == '#') {
446 size_t n;
447
448 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
449 if (node.string[0] == symbol_types[n].n) {
450 node.tag = n;
451 node.string += 2;
452 return copy_node(&node);
453 }
454 }
455 fprintf(stderr, "Unknown type %c\n", node.string[0]);
456 exit(1);
457 }
458 return copy_node(&node);
459 }
460
read_reference(FILE * f)461 static void read_reference(FILE *f)
462 {
463 while (!feof(f)) {
464 struct string_list *defn = NULL;
465 struct string_list *sym, *def;
466 int is_extern = 0, is_override = 0;
467 struct symbol *subsym;
468
469 sym = read_node(f);
470 if (sym && sym->tag == SYM_NORMAL &&
471 !strcmp(sym->string, "override")) {
472 is_override = 1;
473 free_node(sym);
474 sym = read_node(f);
475 }
476 if (!sym)
477 continue;
478 def = read_node(f);
479 if (def && def->tag == SYM_NORMAL &&
480 !strcmp(def->string, "extern")) {
481 is_extern = 1;
482 free_node(def);
483 def = read_node(f);
484 }
485 while (def) {
486 def->next = defn;
487 defn = def;
488 def = read_node(f);
489 }
490 subsym = add_reference_symbol(sym->string, sym->tag,
491 defn, is_extern);
492 subsym->is_override = is_override;
493 free_node(sym);
494 }
495 }
496
print_node(FILE * f,struct string_list * list)497 static void print_node(FILE * f, struct string_list *list)
498 {
499 if (symbol_types[list->tag].n) {
500 putc(symbol_types[list->tag].n, f);
501 putc('#', f);
502 }
503 fputs(list->string, f);
504 }
505
print_list(FILE * f,struct string_list * list)506 static void print_list(FILE * f, struct string_list *list)
507 {
508 struct string_list **e, **b;
509 struct string_list *tmp, **tmp2;
510 int elem = 1;
511
512 if (list == NULL) {
513 fputs("(nil)", f);
514 return;
515 }
516
517 tmp = list;
518 while ((tmp = tmp->next) != NULL)
519 elem++;
520
521 b = alloca(elem * sizeof(*e));
522 e = b + elem;
523 tmp2 = e - 1;
524
525 (*tmp2--) = list;
526 while ((list = list->next) != NULL)
527 *(tmp2--) = list;
528
529 while (b != e) {
530 print_node(f, *b++);
531 putc(' ', f);
532 }
533 }
534
expand_and_crc_sym(struct symbol * sym,unsigned long crc)535 static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
536 {
537 struct string_list *list = sym->defn;
538 struct string_list **e, **b;
539 struct string_list *tmp, **tmp2;
540 int elem = 1;
541
542 if (!list)
543 return crc;
544
545 tmp = list;
546 while ((tmp = tmp->next) != NULL)
547 elem++;
548
549 b = alloca(elem * sizeof(*e));
550 e = b + elem;
551 tmp2 = e - 1;
552
553 *(tmp2--) = list;
554 while ((list = list->next) != NULL)
555 *(tmp2--) = list;
556
557 while (b != e) {
558 struct string_list *cur;
559 struct symbol *subsym;
560
561 cur = *(b++);
562 switch (cur->tag) {
563 case SYM_NORMAL:
564 if (flag_dump_defs)
565 fprintf(debugfile, "%s ", cur->string);
566 crc = partial_crc32(cur->string, crc);
567 crc = partial_crc32_one(' ', crc);
568 break;
569
570 case SYM_ENUM_CONST:
571 case SYM_TYPEDEF:
572 subsym = find_symbol(cur->string, cur->tag, 0);
573 /* FIXME: Bad reference files can segfault here. */
574 if (subsym->expansion_trail) {
575 if (flag_dump_defs)
576 fprintf(debugfile, "%s ", cur->string);
577 crc = partial_crc32(cur->string, crc);
578 crc = partial_crc32_one(' ', crc);
579 } else {
580 subsym->expansion_trail = expansion_trail;
581 expansion_trail = subsym;
582 crc = expand_and_crc_sym(subsym, crc);
583 }
584 break;
585
586 case SYM_STRUCT:
587 case SYM_UNION:
588 case SYM_ENUM:
589 subsym = find_symbol(cur->string, cur->tag, 0);
590 if (!subsym) {
591 struct string_list *n;
592
593 error_with_pos("expand undefined %s %s",
594 symbol_types[cur->tag].name,
595 cur->string);
596 n = concat_list(mk_node
597 (symbol_types[cur->tag].name),
598 mk_node(cur->string),
599 mk_node("{"),
600 mk_node("UNKNOWN"),
601 mk_node("}"), NULL);
602 subsym =
603 add_symbol(cur->string, cur->tag, n, 0);
604 }
605 if (subsym->expansion_trail) {
606 if (flag_dump_defs) {
607 fprintf(debugfile, "%s %s ",
608 symbol_types[cur->tag].name,
609 cur->string);
610 }
611
612 crc = partial_crc32(symbol_types[cur->tag].name,
613 crc);
614 crc = partial_crc32_one(' ', crc);
615 crc = partial_crc32(cur->string, crc);
616 crc = partial_crc32_one(' ', crc);
617 } else {
618 subsym->expansion_trail = expansion_trail;
619 expansion_trail = subsym;
620 crc = expand_and_crc_sym(subsym, crc);
621 }
622 break;
623 }
624 }
625
626 {
627 static struct symbol **end = &visited_symbols;
628
629 if (!sym->visited) {
630 *end = sym;
631 end = &sym->visited;
632 sym->visited = (struct symbol *)-1L;
633 }
634 }
635
636 return crc;
637 }
638
export_symbol(const char * name)639 void export_symbol(const char *name)
640 {
641 struct symbol *sym;
642
643 sym = find_symbol(name, SYM_NORMAL, 0);
644 if (!sym)
645 error_with_pos("export undefined symbol %s", name);
646 else {
647 unsigned long crc;
648 int has_changed = 0;
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, "%s: %s: modversion "
667 "changed because of changes "
668 "in ", flag_preserve ? "error" :
669 "warning", name);
670 } else
671 fprintf(stderr, ", ");
672 print_type_name(sym->type, sym->name);
673 if (sym->status == STATUS_DEFINED)
674 fprintf(stderr, " (became defined)");
675 has_changed = 1;
676 if (flag_preserve)
677 errors++;
678 }
679 sym->expansion_trail = 0;
680 sym = n;
681 }
682 if (has_changed)
683 fprintf(stderr, "\n");
684
685 if (flag_dump_defs)
686 fputs(">\n", debugfile);
687
688 printf("#SYMVER %s 0x%08lx\n", name, crc);
689 }
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/%d = %g\n",
842 nsyms, HASH_BUCKETS,
843 (double)nsyms / (double)HASH_BUCKETS);
844 }
845
846 if (dumpfile)
847 fclose(dumpfile);
848
849 return errors != 0;
850 }
851