blob: 2a1a3b84bebabbbfab28cb750d61b256390ccf54 [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,
Sam Ravnborg2ea03892009-01-14 21:38:20 +010046 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
Michal Marek7ec8eda2011-01-18 16:28:06 +010056static const struct {
57 int n;
58 const char *name;
59} symbol_types[] = {
60 [SYM_NORMAL] = { 0, NULL},
61 [SYM_TYPEDEF] = {'t', "typedef"},
62 [SYM_ENUM] = {'e', "enum"},
63 [SYM_STRUCT] = {'s', "struct"},
64 [SYM_UNION] = {'u', "union"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065};
66
Sam Ravnborgce560682006-03-12 23:26:29 +010067static int equal_list(struct string_list *a, struct string_list *b);
68static void print_list(FILE * f, struct string_list *list);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -080069static void print_location(void);
70static void print_type_name(enum symbol_type type, const char *name);
Sam Ravnborgce560682006-03-12 23:26:29 +010071
Linus Torvalds1da177e2005-04-16 15:20:36 -070072/*----------------------------------------------------------------------*/
73
Sam Ravnborg78c041532006-03-12 22:59:36 +010074static const unsigned int crctab32[] = {
75 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
76 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
77 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
78 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
79 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
80 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
81 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
82 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
83 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
84 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
85 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
86 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
87 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
88 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
89 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
90 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
91 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
92 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
93 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
94 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
95 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
96 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
97 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
98 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
99 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
100 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
101 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
102 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
103 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
104 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
105 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
106 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
107 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
108 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
109 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
110 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
111 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
112 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
113 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
114 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
115 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
116 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
117 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
118 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
119 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
120 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
121 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
122 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
123 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
124 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
125 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
126 0x2d02ef8dU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127};
128
Sam Ravnborgce560682006-03-12 23:26:29 +0100129static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100131 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132}
133
Sam Ravnborgce560682006-03-12 23:26:29 +0100134static unsigned long partial_crc32(const char *s, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100136 while (*s)
137 crc = partial_crc32_one(*s++, crc);
138 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139}
140
Sam Ravnborgce560682006-03-12 23:26:29 +0100141static unsigned long crc32(const char *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100143 return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144}
145
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146/*----------------------------------------------------------------------*/
147
Sam Ravnborgce560682006-03-12 23:26:29 +0100148static enum symbol_type map_to_ns(enum symbol_type t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100150 if (t == SYM_TYPEDEF)
151 t = SYM_NORMAL;
152 else if (t == SYM_UNION)
153 t = SYM_STRUCT;
154 return t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155}
156
Sam Ravnborg78c041532006-03-12 22:59:36 +0100157struct symbol *find_symbol(const char *name, enum symbol_type ns)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100159 unsigned long h = crc32(name) % HASH_BUCKETS;
160 struct symbol *sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Sam Ravnborg78c041532006-03-12 22:59:36 +0100162 for (sym = symtab[h]; sym; sym = sym->hash_next)
Sam Ravnborgce560682006-03-12 23:26:29 +0100163 if (map_to_ns(sym->type) == map_to_ns(ns) &&
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800164 strcmp(name, sym->name) == 0 &&
165 sym->is_declared)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100166 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 return sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169}
170
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800171static int is_unknown_symbol(struct symbol *sym)
172{
173 struct string_list *defn;
174
175 return ((sym->type == SYM_STRUCT ||
176 sym->type == SYM_UNION ||
177 sym->type == SYM_ENUM) &&
178 (defn = sym->defn) && defn->tag == SYM_NORMAL &&
179 strcmp(defn->string, "}") == 0 &&
180 (defn = defn->next) && defn->tag == SYM_NORMAL &&
181 strcmp(defn->string, "UNKNOWN") == 0 &&
182 (defn = defn->next) && defn->tag == SYM_NORMAL &&
183 strcmp(defn->string, "{") == 0);
184}
185
Ladinu Chandrasingheb7ed6982009-09-22 16:43:42 -0700186static struct symbol *__add_symbol(const char *name, enum symbol_type type,
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800187 struct string_list *defn, int is_extern,
188 int is_reference)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100189{
190 unsigned long h = crc32(name) % HASH_BUCKETS;
191 struct symbol *sym;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800192 enum symbol_status status = STATUS_UNCHANGED;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100193
Sam Ravnborgce560682006-03-12 23:26:29 +0100194 for (sym = symtab[h]; sym; sym = sym->hash_next) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800195 if (map_to_ns(sym->type) == map_to_ns(type) &&
196 strcmp(name, sym->name) == 0) {
197 if (is_reference)
198 /* fall through */ ;
199 else if (sym->type == type &&
200 equal_list(sym->defn, defn)) {
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800201 if (!sym->is_declared && sym->is_override) {
202 print_location();
203 print_type_name(type, name);
204 fprintf(stderr, " modversion is "
205 "unchanged\n");
206 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800207 sym->is_declared = 1;
208 return sym;
209 } else if (!sym->is_declared) {
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800210 if (sym->is_override && flag_preserve) {
211 print_location();
212 fprintf(stderr, "ignoring ");
213 print_type_name(type, name);
214 fprintf(stderr, " modversion change\n");
215 sym->is_declared = 1;
216 return sym;
217 } else {
218 status = is_unknown_symbol(sym) ?
219 STATUS_DEFINED : STATUS_MODIFIED;
220 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800221 } else {
Sam Ravnborg78c041532006-03-12 22:59:36 +0100222 error_with_pos("redefinition of %s", name);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800223 return sym;
224 }
225 break;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100226 }
Sam Ravnborgce560682006-03-12 23:26:29 +0100227 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100228
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800229 if (sym) {
230 struct symbol **psym;
231
232 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
233 if (*psym == sym) {
234 *psym = sym->hash_next;
235 break;
236 }
237 }
238 --nsyms;
239 }
240
Sam Ravnborg78c041532006-03-12 22:59:36 +0100241 sym = xmalloc(sizeof(*sym));
242 sym->name = name;
243 sym->type = type;
244 sym->defn = defn;
245 sym->expansion_trail = NULL;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200246 sym->visited = NULL;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100247 sym->is_extern = is_extern;
248
249 sym->hash_next = symtab[h];
250 symtab[h] = sym;
251
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800252 sym->is_declared = !is_reference;
253 sym->status = status;
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800254 sym->is_override = 0;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800255
Sam Ravnborg78c041532006-03-12 22:59:36 +0100256 if (flag_debug) {
Michal Marek7ec8eda2011-01-18 16:28:06 +0100257 if (symbol_types[type].name)
258 fprintf(debugfile, "Defn for %s %s == <",
259 symbol_types[type].name, name);
260 else
261 fprintf(debugfile, "Defn for type%d %s == <",
262 type, name);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100263 if (is_extern)
264 fputs("extern ", debugfile);
265 print_list(debugfile, defn);
266 fputs(">\n", debugfile);
267 }
268
269 ++nsyms;
270 return sym;
271}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800273struct symbol *add_symbol(const char *name, enum symbol_type type,
274 struct string_list *defn, int is_extern)
275{
276 return __add_symbol(name, type, defn, is_extern, 0);
277}
278
Ladinu Chandrasingheb7ed6982009-09-22 16:43:42 -0700279static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800280 struct string_list *defn, int is_extern)
281{
282 return __add_symbol(name, type, defn, is_extern, 1);
283}
284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285/*----------------------------------------------------------------------*/
286
Sam Ravnborgce560682006-03-12 23:26:29 +0100287void free_node(struct string_list *node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100289 free(node->string);
290 free(node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291}
292
Sam Ravnborg78c041532006-03-12 22:59:36 +0100293void free_list(struct string_list *s, struct string_list *e)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100295 while (s != e) {
296 struct string_list *next = s->next;
297 free_node(s);
298 s = next;
299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300}
301
Sam Ravnborgce560682006-03-12 23:26:29 +0100302struct string_list *copy_node(struct string_list *node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100304 struct string_list *newnode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Sam Ravnborg78c041532006-03-12 22:59:36 +0100306 newnode = xmalloc(sizeof(*newnode));
307 newnode->string = xstrdup(node->string);
308 newnode->tag = node->tag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Sam Ravnborg78c041532006-03-12 22:59:36 +0100310 return newnode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311}
312
Sam Ravnborgce560682006-03-12 23:26:29 +0100313static int equal_list(struct string_list *a, struct string_list *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100315 while (a && b) {
316 if (a->tag != b->tag || strcmp(a->string, b->string))
317 return 0;
318 a = a->next;
319 b = b->next;
320 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
Sam Ravnborg78c041532006-03-12 22:59:36 +0100322 return !a && !b;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323}
324
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800325#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
326
Ladinu Chandrasingheb7ed6982009-09-22 16:43:42 -0700327static struct string_list *read_node(FILE *f)
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800328{
329 char buffer[256];
330 struct string_list node = {
331 .string = buffer,
332 .tag = SYM_NORMAL };
333 int c;
334
335 while ((c = fgetc(f)) != EOF) {
336 if (c == ' ') {
337 if (node.string == buffer)
338 continue;
339 break;
340 } else if (c == '\n') {
341 if (node.string == buffer)
342 return NULL;
343 ungetc(c, f);
344 break;
345 }
346 if (node.string >= buffer + sizeof(buffer) - 1) {
347 fprintf(stderr, "Token too long\n");
348 exit(1);
349 }
350 *node.string++ = c;
351 }
352 if (node.string == buffer)
353 return NULL;
354 *node.string = 0;
355 node.string = buffer;
356
357 if (node.string[1] == '#') {
358 int n;
359
Michal Marek7ec8eda2011-01-18 16:28:06 +0100360 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
361 if (node.string[0] == symbol_types[n].n) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800362 node.tag = n;
363 node.string += 2;
364 return copy_node(&node);
365 }
366 }
367 fprintf(stderr, "Unknown type %c\n", node.string[0]);
368 exit(1);
369 }
370 return copy_node(&node);
371}
372
373static void read_reference(FILE *f)
374{
375 while (!feof(f)) {
376 struct string_list *defn = NULL;
377 struct string_list *sym, *def;
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800378 int is_extern = 0, is_override = 0;
379 struct symbol *subsym;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800380
381 sym = read_node(f);
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800382 if (sym && sym->tag == SYM_NORMAL &&
383 !strcmp(sym->string, "override")) {
384 is_override = 1;
385 free_node(sym);
386 sym = read_node(f);
387 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800388 if (!sym)
389 continue;
390 def = read_node(f);
391 if (def && def->tag == SYM_NORMAL &&
392 !strcmp(def->string, "extern")) {
393 is_extern = 1;
394 free_node(def);
395 def = read_node(f);
396 }
397 while (def) {
398 def->next = defn;
399 defn = def;
400 def = read_node(f);
401 }
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800402 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800403 defn, is_extern);
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800404 subsym->is_override = is_override;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800405 free_node(sym);
406 }
407}
408
Sam Ravnborgce560682006-03-12 23:26:29 +0100409static void print_node(FILE * f, struct string_list *list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410{
Michal Marek7ec8eda2011-01-18 16:28:06 +0100411 if (symbol_types[list->tag].n) {
412 putc(symbol_types[list->tag].n, f);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100413 putc('#', f);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100414 }
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200415 fputs(list->string, f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416}
417
Sam Ravnborgce560682006-03-12 23:26:29 +0100418static void print_list(FILE * f, struct string_list *list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100420 struct string_list **e, **b;
421 struct string_list *tmp, **tmp2;
422 int elem = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Sam Ravnborg78c041532006-03-12 22:59:36 +0100424 if (list == NULL) {
425 fputs("(nil)", f);
426 return;
427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Sam Ravnborg78c041532006-03-12 22:59:36 +0100429 tmp = list;
430 while ((tmp = tmp->next) != NULL)
431 elem++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Sam Ravnborg78c041532006-03-12 22:59:36 +0100433 b = alloca(elem * sizeof(*e));
434 e = b + elem;
435 tmp2 = e - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Sam Ravnborg78c041532006-03-12 22:59:36 +0100437 (*tmp2--) = list;
438 while ((list = list->next) != NULL)
439 *(tmp2--) = list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Sam Ravnborg78c041532006-03-12 22:59:36 +0100441 while (b != e) {
442 print_node(f, *b++);
443 putc(' ', f);
444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445}
446
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200447static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200449 struct string_list *list = sym->defn;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100450 struct string_list **e, **b;
451 struct string_list *tmp, **tmp2;
452 int elem = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
Sam Ravnborg78c041532006-03-12 22:59:36 +0100454 if (!list)
455 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
Sam Ravnborg78c041532006-03-12 22:59:36 +0100457 tmp = list;
458 while ((tmp = tmp->next) != NULL)
459 elem++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Sam Ravnborg78c041532006-03-12 22:59:36 +0100461 b = alloca(elem * sizeof(*e));
462 e = b + elem;
463 tmp2 = e - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Sam Ravnborg78c041532006-03-12 22:59:36 +0100465 *(tmp2--) = list;
466 while ((list = list->next) != NULL)
467 *(tmp2--) = list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Sam Ravnborg78c041532006-03-12 22:59:36 +0100469 while (b != e) {
470 struct string_list *cur;
471 struct symbol *subsym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Sam Ravnborg78c041532006-03-12 22:59:36 +0100473 cur = *(b++);
474 switch (cur->tag) {
475 case SYM_NORMAL:
476 if (flag_dump_defs)
477 fprintf(debugfile, "%s ", cur->string);
478 crc = partial_crc32(cur->string, crc);
479 crc = partial_crc32_one(' ', crc);
480 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Sam Ravnborg78c041532006-03-12 22:59:36 +0100482 case SYM_TYPEDEF:
483 subsym = find_symbol(cur->string, cur->tag);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800484 /* FIXME: Bad reference files can segfault here. */
Sam Ravnborg78c041532006-03-12 22:59:36 +0100485 if (subsym->expansion_trail) {
486 if (flag_dump_defs)
487 fprintf(debugfile, "%s ", cur->string);
488 crc = partial_crc32(cur->string, crc);
489 crc = partial_crc32_one(' ', crc);
490 } else {
491 subsym->expansion_trail = expansion_trail;
492 expansion_trail = subsym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200493 crc = expand_and_crc_sym(subsym, crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100494 }
495 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Sam Ravnborg78c041532006-03-12 22:59:36 +0100497 case SYM_STRUCT:
498 case SYM_UNION:
499 case SYM_ENUM:
500 subsym = find_symbol(cur->string, cur->tag);
501 if (!subsym) {
502 struct string_list *n, *t = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503
Sam Ravnborg78c041532006-03-12 22:59:36 +0100504 error_with_pos("expand undefined %s %s",
Michal Marek7ec8eda2011-01-18 16:28:06 +0100505 symbol_types[cur->tag].name,
Sam Ravnborg78c041532006-03-12 22:59:36 +0100506 cur->string);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Sam Ravnborg78c041532006-03-12 22:59:36 +0100508 n = xmalloc(sizeof(*n));
Michal Marek7ec8eda2011-01-18 16:28:06 +0100509 n->string = xstrdup(symbol_types[cur->tag].name);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100510 n->tag = SYM_NORMAL;
511 n->next = t;
512 t = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Sam Ravnborg78c041532006-03-12 22:59:36 +0100514 n = xmalloc(sizeof(*n));
515 n->string = xstrdup(cur->string);
516 n->tag = SYM_NORMAL;
517 n->next = t;
518 t = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Sam Ravnborg78c041532006-03-12 22:59:36 +0100520 n = xmalloc(sizeof(*n));
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800521 n->string = xstrdup("{");
Sam Ravnborg78c041532006-03-12 22:59:36 +0100522 n->tag = SYM_NORMAL;
523 n->next = t;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800524 t = n;
525
526 n = xmalloc(sizeof(*n));
527 n->string = xstrdup("UNKNOWN");
528 n->tag = SYM_NORMAL;
529 n->next = t;
530 t = n;
531
532 n = xmalloc(sizeof(*n));
533 n->string = xstrdup("}");
534 n->tag = SYM_NORMAL;
535 n->next = t;
536 t = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Sam Ravnborg78c041532006-03-12 22:59:36 +0100538 subsym =
539 add_symbol(cur->string, cur->tag, n, 0);
540 }
541 if (subsym->expansion_trail) {
542 if (flag_dump_defs) {
543 fprintf(debugfile, "%s %s ",
Michal Marek7ec8eda2011-01-18 16:28:06 +0100544 symbol_types[cur->tag].name,
Sam Ravnborg78c041532006-03-12 22:59:36 +0100545 cur->string);
546 }
547
Michal Marek7ec8eda2011-01-18 16:28:06 +0100548 crc = partial_crc32(symbol_types[cur->tag].name,
Sam Ravnborgce560682006-03-12 23:26:29 +0100549 crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100550 crc = partial_crc32_one(' ', crc);
551 crc = partial_crc32(cur->string, crc);
552 crc = partial_crc32_one(' ', crc);
553 } else {
554 subsym->expansion_trail = expansion_trail;
555 expansion_trail = subsym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200556 crc = expand_and_crc_sym(subsym, crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100557 }
558 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200562 {
563 static struct symbol **end = &visited_symbols;
564
565 if (!sym->visited) {
566 *end = sym;
567 end = &sym->visited;
568 sym->visited = (struct symbol *)-1L;
569 }
570 }
571
Sam Ravnborg78c041532006-03-12 22:59:36 +0100572 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573}
574
Sam Ravnborg78c041532006-03-12 22:59:36 +0100575void export_symbol(const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100577 struct symbol *sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Sam Ravnborg78c041532006-03-12 22:59:36 +0100579 sym = find_symbol(name, SYM_NORMAL);
580 if (!sym)
581 error_with_pos("export undefined symbol %s", name);
582 else {
583 unsigned long crc;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800584 int has_changed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Sam Ravnborg78c041532006-03-12 22:59:36 +0100586 if (flag_dump_defs)
587 fprintf(debugfile, "Export %s == <", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Sam Ravnborg78c041532006-03-12 22:59:36 +0100589 expansion_trail = (struct symbol *)-1L;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800591 sym->expansion_trail = expansion_trail;
592 expansion_trail = sym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200593 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Sam Ravnborg78c041532006-03-12 22:59:36 +0100595 sym = expansion_trail;
596 while (sym != (struct symbol *)-1L) {
597 struct symbol *n = sym->expansion_trail;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800598
599 if (sym->status != STATUS_UNCHANGED) {
600 if (!has_changed) {
601 print_location();
602 fprintf(stderr, "%s: %s: modversion "
603 "changed because of changes "
604 "in ", flag_preserve ? "error" :
605 "warning", name);
606 } else
607 fprintf(stderr, ", ");
608 print_type_name(sym->type, sym->name);
609 if (sym->status == STATUS_DEFINED)
610 fprintf(stderr, " (became defined)");
611 has_changed = 1;
612 if (flag_preserve)
613 errors++;
614 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100615 sym->expansion_trail = 0;
616 sym = n;
617 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800618 if (has_changed)
619 fprintf(stderr, "\n");
Sam Ravnborg78c041532006-03-12 22:59:36 +0100620
621 if (flag_dump_defs)
622 fputs(">\n", debugfile);
623
Sam Ravnborg2ea03892009-01-14 21:38:20 +0100624 /* Used as a linker script. */
625 printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627}
628
629/*----------------------------------------------------------------------*/
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800630
631static void print_location(void)
632{
633 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
634}
635
636static void print_type_name(enum symbol_type type, const char *name)
637{
Michal Marek7ec8eda2011-01-18 16:28:06 +0100638 if (symbol_types[type].name)
639 fprintf(stderr, "%s %s", symbol_types[type].name, name);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800640 else
641 fprintf(stderr, "%s", name);
642}
643
Sam Ravnborg78c041532006-03-12 22:59:36 +0100644void error_with_pos(const char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100646 va_list args;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Sam Ravnborg78c041532006-03-12 22:59:36 +0100648 if (flag_warnings) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800649 print_location();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Sam Ravnborg78c041532006-03-12 22:59:36 +0100651 va_start(args, fmt);
652 vfprintf(stderr, fmt, args);
653 va_end(args);
654 putc('\n', stderr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Sam Ravnborg78c041532006-03-12 22:59:36 +0100656 errors++;
657 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658}
659
Sam Ravnborgce560682006-03-12 23:26:29 +0100660static void genksyms_usage(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661{
Sam Ravnborg2ea03892009-01-14 21:38:20 +0100662 fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663#ifdef __GNU_LIBRARY__
Mike Frysinger36091fd2007-11-10 09:32:20 -0500664 " -a, --arch Select architecture\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 " -d, --debug Increment the debug level (repeatable)\n"
666 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800667 " -r, --reference file Read reference symbols from a file\n"
668 " -T, --dump-types file Dump expanded types into file\n"
669 " -p, --preserve Preserve reference modversions or fail\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 " -w, --warnings Enable warnings\n"
671 " -q, --quiet Disable warnings (default)\n"
672 " -h, --help Print this message\n"
673 " -V, --version Print the release version\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100674#else /* __GNU_LIBRARY__ */
Mike Frysinger36091fd2007-11-10 09:32:20 -0500675 " -a Select architecture\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100676 " -d Increment the debug level (repeatable)\n"
677 " -D Dump expanded symbol defs (for debugging only)\n"
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800678 " -r file Read reference symbols from a file\n"
679 " -T file Dump expanded types into file\n"
680 " -p Preserve reference modversions or fail\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100681 " -w Enable warnings\n"
682 " -q Disable warnings (default)\n"
683 " -h Print this message\n"
684 " -V Print the release version\n"
685#endif /* __GNU_LIBRARY__ */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 , stderr);
687}
688
Sam Ravnborg78c041532006-03-12 22:59:36 +0100689int main(int argc, char **argv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800691 FILE *dumpfile = NULL, *ref_file = NULL;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100692 int o;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694#ifdef __GNU_LIBRARY__
Sam Ravnborg78c041532006-03-12 22:59:36 +0100695 struct option long_opts[] = {
696 {"arch", 1, 0, 'a'},
697 {"debug", 0, 0, 'd'},
698 {"warnings", 0, 0, 'w'},
699 {"quiet", 0, 0, 'q'},
700 {"dump", 0, 0, 'D'},
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800701 {"reference", 1, 0, 'r'},
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200702 {"dump-types", 1, 0, 'T'},
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800703 {"preserve", 0, 0, 'p'},
Sam Ravnborg78c041532006-03-12 22:59:36 +0100704 {"version", 0, 0, 'V'},
705 {"help", 0, 0, 'h'},
706 {0, 0, 0, 0}
707 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Sam Ravnborg2ea03892009-01-14 21:38:20 +0100709 while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph",
Sam Ravnborg78c041532006-03-12 22:59:36 +0100710 &long_opts[0], NULL)) != EOF)
711#else /* __GNU_LIBRARY__ */
Sam Ravnborg2ea03892009-01-14 21:38:20 +0100712 while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100713#endif /* __GNU_LIBRARY__ */
714 switch (o) {
715 case 'a':
716 arch = optarg;
717 break;
718 case 'd':
719 flag_debug++;
720 break;
721 case 'w':
722 flag_warnings = 1;
723 break;
724 case 'q':
725 flag_warnings = 0;
726 break;
727 case 'V':
728 fputs("genksyms version 2.5.60\n", stderr);
729 break;
730 case 'D':
731 flag_dump_defs = 1;
732 break;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800733 case 'r':
734 flag_reference = 1;
735 ref_file = fopen(optarg, "r");
736 if (!ref_file) {
737 perror(optarg);
738 return 1;
739 }
740 break;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200741 case 'T':
742 flag_dump_types = 1;
743 dumpfile = fopen(optarg, "w");
744 if (!dumpfile) {
745 perror(optarg);
746 return 1;
747 }
748 break;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800749 case 'p':
750 flag_preserve = 1;
751 break;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100752 case 'h':
753 genksyms_usage();
754 return 0;
755 default:
756 genksyms_usage();
757 return 1;
758 }
Adrian Bunkf606ddf2008-07-23 21:28:50 -0700759 if ((strcmp(arch, "h8300") == 0) || (strcmp(arch, "blackfin") == 0))
Sam Ravnborg78c041532006-03-12 22:59:36 +0100760 mod_prefix = "_";
761 {
762 extern int yydebug;
763 extern int yy_flex_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Sam Ravnborg78c041532006-03-12 22:59:36 +0100765 yydebug = (flag_debug > 1);
766 yy_flex_debug = (flag_debug > 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Sam Ravnborg78c041532006-03-12 22:59:36 +0100768 debugfile = stderr;
769 /* setlinebuf(debugfile); */
770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Alexander Beregalovc64152b2010-01-07 05:22:41 +0300772 if (flag_reference) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800773 read_reference(ref_file);
Alexander Beregalovc64152b2010-01-07 05:22:41 +0300774 fclose(ref_file);
775 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800776
Sam Ravnborg78c041532006-03-12 22:59:36 +0100777 yyparse();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200779 if (flag_dump_types && visited_symbols) {
780 while (visited_symbols != (struct symbol *)-1L) {
781 struct symbol *sym = visited_symbols;
782
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800783 if (sym->is_override)
784 fputs("override ", dumpfile);
Michal Marek7ec8eda2011-01-18 16:28:06 +0100785 if (symbol_types[sym->type].n) {
786 putc(symbol_types[sym->type].n, dumpfile);
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200787 putc('#', dumpfile);
788 }
789 fputs(sym->name, dumpfile);
790 putc(' ', dumpfile);
Andreas Gruenbacher3b40d382008-07-21 04:28:25 +0200791 if (sym->is_extern)
792 fputs("extern ", dumpfile);
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200793 print_list(dumpfile, sym->defn);
794 putc('\n', dumpfile);
795
796 visited_symbols = sym->visited;
797 sym->visited = NULL;
798 }
799 }
800
Sam Ravnborg78c041532006-03-12 22:59:36 +0100801 if (flag_debug) {
802 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
803 nsyms, HASH_BUCKETS,
804 (double)nsyms / (double)HASH_BUCKETS);
805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
Sam Ravnborg78c041532006-03-12 22:59:36 +0100807 return errors != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808}