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