blob: ddac1746908e04ba6cced6cdfffa214148093eb4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* Generate kernel symbol version hashes.
2 Copyright 1996, 1997 Linux International.
3
4 New implementation contributed by Richard Henderson <rth@tamu.edu>
5 Based on original work by Bjorn Ekwall <bj0rn@blox.se>
6
7 This file was part of the Linux modutils 2.4.22: moved back into the
8 kernel sources by Rusty Russell/Kai Germaschewski.
9
10 This program is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 2 of the License, or (at your
13 option) any later version.
14
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <assert.h>
29#include <stdarg.h>
30#ifdef __GNU_LIBRARY__
31#include <getopt.h>
Sam Ravnborg78c041532006-03-12 22:59:36 +010032#endif /* __GNU_LIBRARY__ */
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34#include "genksyms.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/*----------------------------------------------------------------------*/
36
37#define HASH_BUCKETS 4096
38
39static struct symbol *symtab[HASH_BUCKETS];
Sam Ravnborgce560682006-03-12 23:26:29 +010040static FILE *debugfile;
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42int cur_line = 1;
Sam Ravnborgce560682006-03-12 23:26:29 +010043char *cur_filename;
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -080045static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
46 flag_preserve, flag_warnings;
Sam Ravnborgce560682006-03-12 23:26:29 +010047static const char *arch = "";
48static const char *mod_prefix = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50static int errors;
51static int nsyms;
52
53static struct symbol *expansion_trail;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +020054static struct symbol *visited_symbols;
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Sam Ravnborg78c041532006-03-12 22:59:36 +010056static const char *const symbol_type_name[] = {
57 "normal", "typedef", "enum", "struct", "union"
Linus Torvalds1da177e2005-04-16 15:20:36 -070058};
59
Sam Ravnborgce560682006-03-12 23:26:29 +010060static int equal_list(struct string_list *a, struct string_list *b);
61static void print_list(FILE * f, struct string_list *list);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -080062static void print_location(void);
63static void print_type_name(enum symbol_type type, const char *name);
Sam Ravnborgce560682006-03-12 23:26:29 +010064
Linus Torvalds1da177e2005-04-16 15:20:36 -070065/*----------------------------------------------------------------------*/
66
Sam Ravnborg78c041532006-03-12 22:59:36 +010067static const unsigned int crctab32[] = {
68 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
69 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
70 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
71 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
72 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
73 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
74 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
75 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
76 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
77 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
78 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
79 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
80 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
81 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
82 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
83 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
84 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
85 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
86 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
87 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
88 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
89 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
90 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
91 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
92 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
93 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
94 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
95 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
96 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
97 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
98 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
99 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
100 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
101 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
102 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
103 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
104 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
105 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
106 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
107 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
108 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
109 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
110 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
111 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
112 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
113 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
114 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
115 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
116 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
117 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
118 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
119 0x2d02ef8dU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120};
121
Sam Ravnborgce560682006-03-12 23:26:29 +0100122static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100124 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
126
Sam Ravnborgce560682006-03-12 23:26:29 +0100127static unsigned long partial_crc32(const char *s, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100129 while (*s)
130 crc = partial_crc32_one(*s++, crc);
131 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132}
133
Sam Ravnborgce560682006-03-12 23:26:29 +0100134static unsigned long crc32(const char *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100136 return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137}
138
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139/*----------------------------------------------------------------------*/
140
Sam Ravnborgce560682006-03-12 23:26:29 +0100141static enum symbol_type map_to_ns(enum symbol_type t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100143 if (t == SYM_TYPEDEF)
144 t = SYM_NORMAL;
145 else if (t == SYM_UNION)
146 t = SYM_STRUCT;
147 return t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148}
149
Sam Ravnborg78c041532006-03-12 22:59:36 +0100150struct symbol *find_symbol(const char *name, enum symbol_type ns)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100152 unsigned long h = crc32(name) % HASH_BUCKETS;
153 struct symbol *sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
Sam Ravnborg78c041532006-03-12 22:59:36 +0100155 for (sym = symtab[h]; sym; sym = sym->hash_next)
Sam Ravnborgce560682006-03-12 23:26:29 +0100156 if (map_to_ns(sym->type) == map_to_ns(ns) &&
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800157 strcmp(name, sym->name) == 0 &&
158 sym->is_declared)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100159 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 return sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162}
163
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800164static int is_unknown_symbol(struct symbol *sym)
165{
166 struct string_list *defn;
167
168 return ((sym->type == SYM_STRUCT ||
169 sym->type == SYM_UNION ||
170 sym->type == SYM_ENUM) &&
171 (defn = sym->defn) && defn->tag == SYM_NORMAL &&
172 strcmp(defn->string, "}") == 0 &&
173 (defn = defn->next) && defn->tag == SYM_NORMAL &&
174 strcmp(defn->string, "UNKNOWN") == 0 &&
175 (defn = defn->next) && defn->tag == SYM_NORMAL &&
176 strcmp(defn->string, "{") == 0);
177}
178
179struct symbol *__add_symbol(const char *name, enum symbol_type type,
180 struct string_list *defn, int is_extern,
181 int is_reference)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100182{
183 unsigned long h = crc32(name) % HASH_BUCKETS;
184 struct symbol *sym;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800185 enum symbol_status status = STATUS_UNCHANGED;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100186
Sam Ravnborgce560682006-03-12 23:26:29 +0100187 for (sym = symtab[h]; sym; sym = sym->hash_next) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800188 if (map_to_ns(sym->type) == map_to_ns(type) &&
189 strcmp(name, sym->name) == 0) {
190 if (is_reference)
191 /* fall through */ ;
192 else if (sym->type == type &&
193 equal_list(sym->defn, defn)) {
194 sym->is_declared = 1;
195 return sym;
196 } else if (!sym->is_declared) {
197 status = is_unknown_symbol(sym) ?
198 STATUS_DEFINED : STATUS_MODIFIED;
199 } else {
Sam Ravnborg78c041532006-03-12 22:59:36 +0100200 error_with_pos("redefinition of %s", name);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800201 return sym;
202 }
203 break;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100204 }
Sam Ravnborgce560682006-03-12 23:26:29 +0100205 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100206
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800207 if (sym) {
208 struct symbol **psym;
209
210 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
211 if (*psym == sym) {
212 *psym = sym->hash_next;
213 break;
214 }
215 }
216 --nsyms;
217 }
218
Sam Ravnborg78c041532006-03-12 22:59:36 +0100219 sym = xmalloc(sizeof(*sym));
220 sym->name = name;
221 sym->type = type;
222 sym->defn = defn;
223 sym->expansion_trail = NULL;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200224 sym->visited = NULL;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100225 sym->is_extern = is_extern;
226
227 sym->hash_next = symtab[h];
228 symtab[h] = sym;
229
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800230 sym->is_declared = !is_reference;
231 sym->status = status;
232
Sam Ravnborg78c041532006-03-12 22:59:36 +0100233 if (flag_debug) {
234 fprintf(debugfile, "Defn for %s %s == <",
235 symbol_type_name[type], name);
236 if (is_extern)
237 fputs("extern ", debugfile);
238 print_list(debugfile, defn);
239 fputs(">\n", debugfile);
240 }
241
242 ++nsyms;
243 return sym;
244}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800246struct symbol *add_symbol(const char *name, enum symbol_type type,
247 struct string_list *defn, int is_extern)
248{
249 return __add_symbol(name, type, defn, is_extern, 0);
250}
251
252struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
253 struct string_list *defn, int is_extern)
254{
255 return __add_symbol(name, type, defn, is_extern, 1);
256}
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258/*----------------------------------------------------------------------*/
259
Sam Ravnborgce560682006-03-12 23:26:29 +0100260void free_node(struct string_list *node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100262 free(node->string);
263 free(node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
265
Sam Ravnborg78c041532006-03-12 22:59:36 +0100266void free_list(struct string_list *s, struct string_list *e)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100268 while (s != e) {
269 struct string_list *next = s->next;
270 free_node(s);
271 s = next;
272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273}
274
Sam Ravnborgce560682006-03-12 23:26:29 +0100275struct string_list *copy_node(struct string_list *node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100277 struct string_list *newnode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Sam Ravnborg78c041532006-03-12 22:59:36 +0100279 newnode = xmalloc(sizeof(*newnode));
280 newnode->string = xstrdup(node->string);
281 newnode->tag = node->tag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Sam Ravnborg78c041532006-03-12 22:59:36 +0100283 return newnode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284}
285
Sam Ravnborgce560682006-03-12 23:26:29 +0100286static int equal_list(struct string_list *a, struct string_list *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100288 while (a && b) {
289 if (a->tag != b->tag || strcmp(a->string, b->string))
290 return 0;
291 a = a->next;
292 b = b->next;
293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Sam Ravnborg78c041532006-03-12 22:59:36 +0100295 return !a && !b;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296}
297
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800298#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
299
300struct string_list *read_node(FILE *f)
301{
302 char buffer[256];
303 struct string_list node = {
304 .string = buffer,
305 .tag = SYM_NORMAL };
306 int c;
307
308 while ((c = fgetc(f)) != EOF) {
309 if (c == ' ') {
310 if (node.string == buffer)
311 continue;
312 break;
313 } else if (c == '\n') {
314 if (node.string == buffer)
315 return NULL;
316 ungetc(c, f);
317 break;
318 }
319 if (node.string >= buffer + sizeof(buffer) - 1) {
320 fprintf(stderr, "Token too long\n");
321 exit(1);
322 }
323 *node.string++ = c;
324 }
325 if (node.string == buffer)
326 return NULL;
327 *node.string = 0;
328 node.string = buffer;
329
330 if (node.string[1] == '#') {
331 int n;
332
333 for (n = 0; n < ARRAY_SIZE(symbol_type_name); n++) {
334 if (node.string[0] == symbol_type_name[n][0]) {
335 node.tag = n;
336 node.string += 2;
337 return copy_node(&node);
338 }
339 }
340 fprintf(stderr, "Unknown type %c\n", node.string[0]);
341 exit(1);
342 }
343 return copy_node(&node);
344}
345
346static void read_reference(FILE *f)
347{
348 while (!feof(f)) {
349 struct string_list *defn = NULL;
350 struct string_list *sym, *def;
351 int is_extern = 0;
352
353 sym = read_node(f);
354 if (!sym)
355 continue;
356 def = read_node(f);
357 if (def && def->tag == SYM_NORMAL &&
358 !strcmp(def->string, "extern")) {
359 is_extern = 1;
360 free_node(def);
361 def = read_node(f);
362 }
363 while (def) {
364 def->next = defn;
365 defn = def;
366 def = read_node(f);
367 }
368 add_reference_symbol(xstrdup(sym->string), sym->tag,
369 defn, is_extern);
370 free_node(sym);
371 }
372}
373
Sam Ravnborgce560682006-03-12 23:26:29 +0100374static void print_node(FILE * f, struct string_list *list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200376 if (list->tag != SYM_NORMAL) {
377 putc(symbol_type_name[list->tag][0], f);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100378 putc('#', f);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100379 }
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200380 fputs(list->string, f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381}
382
Sam Ravnborgce560682006-03-12 23:26:29 +0100383static void print_list(FILE * f, struct string_list *list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100385 struct string_list **e, **b;
386 struct string_list *tmp, **tmp2;
387 int elem = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Sam Ravnborg78c041532006-03-12 22:59:36 +0100389 if (list == NULL) {
390 fputs("(nil)", f);
391 return;
392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Sam Ravnborg78c041532006-03-12 22:59:36 +0100394 tmp = list;
395 while ((tmp = tmp->next) != NULL)
396 elem++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Sam Ravnborg78c041532006-03-12 22:59:36 +0100398 b = alloca(elem * sizeof(*e));
399 e = b + elem;
400 tmp2 = e - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Sam Ravnborg78c041532006-03-12 22:59:36 +0100402 (*tmp2--) = list;
403 while ((list = list->next) != NULL)
404 *(tmp2--) = list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Sam Ravnborg78c041532006-03-12 22:59:36 +0100406 while (b != e) {
407 print_node(f, *b++);
408 putc(' ', f);
409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410}
411
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200412static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200414 struct string_list *list = sym->defn;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100415 struct string_list **e, **b;
416 struct string_list *tmp, **tmp2;
417 int elem = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Sam Ravnborg78c041532006-03-12 22:59:36 +0100419 if (!list)
420 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Sam Ravnborg78c041532006-03-12 22:59:36 +0100422 tmp = list;
423 while ((tmp = tmp->next) != NULL)
424 elem++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425
Sam Ravnborg78c041532006-03-12 22:59:36 +0100426 b = alloca(elem * sizeof(*e));
427 e = b + elem;
428 tmp2 = e - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
Sam Ravnborg78c041532006-03-12 22:59:36 +0100430 *(tmp2--) = list;
431 while ((list = list->next) != NULL)
432 *(tmp2--) = list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
Sam Ravnborg78c041532006-03-12 22:59:36 +0100434 while (b != e) {
435 struct string_list *cur;
436 struct symbol *subsym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Sam Ravnborg78c041532006-03-12 22:59:36 +0100438 cur = *(b++);
439 switch (cur->tag) {
440 case SYM_NORMAL:
441 if (flag_dump_defs)
442 fprintf(debugfile, "%s ", cur->string);
443 crc = partial_crc32(cur->string, crc);
444 crc = partial_crc32_one(' ', crc);
445 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
Sam Ravnborg78c041532006-03-12 22:59:36 +0100447 case SYM_TYPEDEF:
448 subsym = find_symbol(cur->string, cur->tag);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800449 /* FIXME: Bad reference files can segfault here. */
Sam Ravnborg78c041532006-03-12 22:59:36 +0100450 if (subsym->expansion_trail) {
451 if (flag_dump_defs)
452 fprintf(debugfile, "%s ", cur->string);
453 crc = partial_crc32(cur->string, crc);
454 crc = partial_crc32_one(' ', crc);
455 } else {
456 subsym->expansion_trail = expansion_trail;
457 expansion_trail = subsym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200458 crc = expand_and_crc_sym(subsym, crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100459 }
460 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Sam Ravnborg78c041532006-03-12 22:59:36 +0100462 case SYM_STRUCT:
463 case SYM_UNION:
464 case SYM_ENUM:
465 subsym = find_symbol(cur->string, cur->tag);
466 if (!subsym) {
467 struct string_list *n, *t = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Sam Ravnborg78c041532006-03-12 22:59:36 +0100469 error_with_pos("expand undefined %s %s",
470 symbol_type_name[cur->tag],
471 cur->string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Sam Ravnborg78c041532006-03-12 22:59:36 +0100473 n = xmalloc(sizeof(*n));
474 n->string = xstrdup(symbol_type_name[cur->tag]);
475 n->tag = SYM_NORMAL;
476 n->next = t;
477 t = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Sam Ravnborg78c041532006-03-12 22:59:36 +0100479 n = xmalloc(sizeof(*n));
480 n->string = xstrdup(cur->string);
481 n->tag = SYM_NORMAL;
482 n->next = t;
483 t = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Sam Ravnborg78c041532006-03-12 22:59:36 +0100485 n = xmalloc(sizeof(*n));
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800486 n->string = xstrdup("{");
Sam Ravnborg78c041532006-03-12 22:59:36 +0100487 n->tag = SYM_NORMAL;
488 n->next = t;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800489 t = n;
490
491 n = xmalloc(sizeof(*n));
492 n->string = xstrdup("UNKNOWN");
493 n->tag = SYM_NORMAL;
494 n->next = t;
495 t = n;
496
497 n = xmalloc(sizeof(*n));
498 n->string = xstrdup("}");
499 n->tag = SYM_NORMAL;
500 n->next = t;
501 t = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Sam Ravnborg78c041532006-03-12 22:59:36 +0100503 subsym =
504 add_symbol(cur->string, cur->tag, n, 0);
505 }
506 if (subsym->expansion_trail) {
507 if (flag_dump_defs) {
508 fprintf(debugfile, "%s %s ",
509 symbol_type_name[cur->tag],
510 cur->string);
511 }
512
Sam Ravnborgce560682006-03-12 23:26:29 +0100513 crc = partial_crc32(symbol_type_name[cur->tag],
514 crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100515 crc = partial_crc32_one(' ', crc);
516 crc = partial_crc32(cur->string, crc);
517 crc = partial_crc32_one(' ', crc);
518 } else {
519 subsym->expansion_trail = expansion_trail;
520 expansion_trail = subsym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200521 crc = expand_and_crc_sym(subsym, crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100522 }
523 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200527 {
528 static struct symbol **end = &visited_symbols;
529
530 if (!sym->visited) {
531 *end = sym;
532 end = &sym->visited;
533 sym->visited = (struct symbol *)-1L;
534 }
535 }
536
Sam Ravnborg78c041532006-03-12 22:59:36 +0100537 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538}
539
Sam Ravnborg78c041532006-03-12 22:59:36 +0100540void export_symbol(const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100542 struct symbol *sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
Sam Ravnborg78c041532006-03-12 22:59:36 +0100544 sym = find_symbol(name, SYM_NORMAL);
545 if (!sym)
546 error_with_pos("export undefined symbol %s", name);
547 else {
548 unsigned long crc;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800549 int has_changed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
Sam Ravnborg78c041532006-03-12 22:59:36 +0100551 if (flag_dump_defs)
552 fprintf(debugfile, "Export %s == <", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553
Sam Ravnborg78c041532006-03-12 22:59:36 +0100554 expansion_trail = (struct symbol *)-1L;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800556 sym->expansion_trail = expansion_trail;
557 expansion_trail = sym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200558 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
Sam Ravnborg78c041532006-03-12 22:59:36 +0100560 sym = expansion_trail;
561 while (sym != (struct symbol *)-1L) {
562 struct symbol *n = sym->expansion_trail;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800563
564 if (sym->status != STATUS_UNCHANGED) {
565 if (!has_changed) {
566 print_location();
567 fprintf(stderr, "%s: %s: modversion "
568 "changed because of changes "
569 "in ", flag_preserve ? "error" :
570 "warning", name);
571 } else
572 fprintf(stderr, ", ");
573 print_type_name(sym->type, sym->name);
574 if (sym->status == STATUS_DEFINED)
575 fprintf(stderr, " (became defined)");
576 has_changed = 1;
577 if (flag_preserve)
578 errors++;
579 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100580 sym->expansion_trail = 0;
581 sym = n;
582 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800583 if (has_changed)
584 fprintf(stderr, "\n");
Sam Ravnborg78c041532006-03-12 22:59:36 +0100585
586 if (flag_dump_defs)
587 fputs(">\n", debugfile);
588
589 /* Used as a linker script. */
590 printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592}
593
594/*----------------------------------------------------------------------*/
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800595
596static void print_location(void)
597{
598 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
599}
600
601static void print_type_name(enum symbol_type type, const char *name)
602{
603 if (type != SYM_NORMAL)
604 fprintf(stderr, "%s %s", symbol_type_name[type], name);
605 else
606 fprintf(stderr, "%s", name);
607}
608
Sam Ravnborg78c041532006-03-12 22:59:36 +0100609void error_with_pos(const char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100611 va_list args;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Sam Ravnborg78c041532006-03-12 22:59:36 +0100613 if (flag_warnings) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800614 print_location();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Sam Ravnborg78c041532006-03-12 22:59:36 +0100616 va_start(args, fmt);
617 vfprintf(stderr, fmt, args);
618 va_end(args);
619 putc('\n', stderr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Sam Ravnborg78c041532006-03-12 22:59:36 +0100621 errors++;
622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623}
624
Sam Ravnborgce560682006-03-12 23:26:29 +0100625static void genksyms_usage(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626{
Mike Frysinger36091fd2007-11-10 09:32:20 -0500627 fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628#ifdef __GNU_LIBRARY__
Mike Frysinger36091fd2007-11-10 09:32:20 -0500629 " -a, --arch Select architecture\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 " -d, --debug Increment the debug level (repeatable)\n"
631 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800632 " -r, --reference file Read reference symbols from a file\n"
633 " -T, --dump-types file Dump expanded types into file\n"
634 " -p, --preserve Preserve reference modversions or fail\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 " -w, --warnings Enable warnings\n"
636 " -q, --quiet Disable warnings (default)\n"
637 " -h, --help Print this message\n"
638 " -V, --version Print the release version\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100639#else /* __GNU_LIBRARY__ */
Mike Frysinger36091fd2007-11-10 09:32:20 -0500640 " -a Select architecture\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100641 " -d Increment the debug level (repeatable)\n"
642 " -D Dump expanded symbol defs (for debugging only)\n"
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800643 " -r file Read reference symbols from a file\n"
644 " -T file Dump expanded types into file\n"
645 " -p Preserve reference modversions or fail\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100646 " -w Enable warnings\n"
647 " -q Disable warnings (default)\n"
648 " -h Print this message\n"
649 " -V Print the release version\n"
650#endif /* __GNU_LIBRARY__ */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 , stderr);
652}
653
Sam Ravnborg78c041532006-03-12 22:59:36 +0100654int main(int argc, char **argv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655{
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800656 FILE *dumpfile = NULL, *ref_file = NULL;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100657 int o;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
659#ifdef __GNU_LIBRARY__
Sam Ravnborg78c041532006-03-12 22:59:36 +0100660 struct option long_opts[] = {
661 {"arch", 1, 0, 'a'},
662 {"debug", 0, 0, 'd'},
663 {"warnings", 0, 0, 'w'},
664 {"quiet", 0, 0, 'q'},
665 {"dump", 0, 0, 'D'},
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800666 {"reference", 1, 0, 'r'},
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200667 {"dump-types", 1, 0, 'T'},
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800668 {"preserve", 0, 0, 'p'},
Sam Ravnborg78c041532006-03-12 22:59:36 +0100669 {"version", 0, 0, 'V'},
670 {"help", 0, 0, 'h'},
671 {0, 0, 0, 0}
672 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800674 while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph",
Sam Ravnborg78c041532006-03-12 22:59:36 +0100675 &long_opts[0], NULL)) != EOF)
676#else /* __GNU_LIBRARY__ */
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800677 while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100678#endif /* __GNU_LIBRARY__ */
679 switch (o) {
680 case 'a':
681 arch = optarg;
682 break;
683 case 'd':
684 flag_debug++;
685 break;
686 case 'w':
687 flag_warnings = 1;
688 break;
689 case 'q':
690 flag_warnings = 0;
691 break;
692 case 'V':
693 fputs("genksyms version 2.5.60\n", stderr);
694 break;
695 case 'D':
696 flag_dump_defs = 1;
697 break;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800698 case 'r':
699 flag_reference = 1;
700 ref_file = fopen(optarg, "r");
701 if (!ref_file) {
702 perror(optarg);
703 return 1;
704 }
705 break;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200706 case 'T':
707 flag_dump_types = 1;
708 dumpfile = fopen(optarg, "w");
709 if (!dumpfile) {
710 perror(optarg);
711 return 1;
712 }
713 break;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800714 case 'p':
715 flag_preserve = 1;
716 break;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100717 case 'h':
718 genksyms_usage();
719 return 0;
720 default:
721 genksyms_usage();
722 return 1;
723 }
Adrian Bunkf606ddf2008-07-23 21:28:50 -0700724 if ((strcmp(arch, "h8300") == 0) || (strcmp(arch, "blackfin") == 0))
Sam Ravnborg78c041532006-03-12 22:59:36 +0100725 mod_prefix = "_";
726 {
727 extern int yydebug;
728 extern int yy_flex_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Sam Ravnborg78c041532006-03-12 22:59:36 +0100730 yydebug = (flag_debug > 1);
731 yy_flex_debug = (flag_debug > 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
Sam Ravnborg78c041532006-03-12 22:59:36 +0100733 debugfile = stderr;
734 /* setlinebuf(debugfile); */
735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800737 if (flag_reference)
738 read_reference(ref_file);
739
Sam Ravnborg78c041532006-03-12 22:59:36 +0100740 yyparse();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200742 if (flag_dump_types && visited_symbols) {
743 while (visited_symbols != (struct symbol *)-1L) {
744 struct symbol *sym = visited_symbols;
745
746 if (sym->type != SYM_NORMAL) {
747 putc(symbol_type_name[sym->type][0], dumpfile);
748 putc('#', dumpfile);
749 }
750 fputs(sym->name, dumpfile);
751 putc(' ', dumpfile);
Andreas Gruenbacher3b40d382008-07-21 04:28:25 +0200752 if (sym->is_extern)
753 fputs("extern ", dumpfile);
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200754 print_list(dumpfile, sym->defn);
755 putc('\n', dumpfile);
756
757 visited_symbols = sym->visited;
758 sym->visited = NULL;
759 }
760 }
761
Sam Ravnborg78c041532006-03-12 22:59:36 +0100762 if (flag_debug) {
763 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
764 nsyms, HASH_BUCKETS,
765 (double)nsyms / (double)HASH_BUCKETS);
766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Sam Ravnborg78c041532006-03-12 22:59:36 +0100768 return errors != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769}