blob: e007840f45b91532a434ca5397ac5e7471b34ea9 [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;
Michal Marek2c5925d2011-10-08 01:18:35 +020043char *cur_filename, *source_file;
44int in_source_file;
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -080046static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
Ard Biesheuvel56067812017-02-03 09:54:05 +000047 flag_preserve, flag_warnings, flag_rel_crcs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49static int errors;
50static int nsyms;
51
52static struct symbol *expansion_trail;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +020053static struct symbol *visited_symbols;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Michal Marek7ec8eda2011-01-18 16:28:06 +010055static const struct {
56 int n;
57 const char *name;
58} symbol_types[] = {
59 [SYM_NORMAL] = { 0, NULL},
60 [SYM_TYPEDEF] = {'t', "typedef"},
61 [SYM_ENUM] = {'e', "enum"},
62 [SYM_STRUCT] = {'s', "struct"},
63 [SYM_UNION] = {'u', "union"},
Michal Mareke37ddb82011-02-03 23:57:09 +010064 [SYM_ENUM_CONST] = {'E', "enum constant"},
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);
Michal Marek68eb8562011-02-02 23:52:13 +010069static struct string_list *concat_list(struct string_list *start, ...);
70static struct string_list *mk_node(const char *string);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -080071static void print_location(void);
72static void print_type_name(enum symbol_type type, const char *name);
Sam Ravnborgce560682006-03-12 23:26:29 +010073
Linus Torvalds1da177e2005-04-16 15:20:36 -070074/*----------------------------------------------------------------------*/
75
Sam Ravnborg78c041532006-03-12 22:59:36 +010076static const unsigned int crctab32[] = {
77 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
78 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
79 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
80 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
81 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
82 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
83 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
84 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
85 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
86 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
87 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
88 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
89 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
90 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
91 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
92 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
93 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
94 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
95 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
96 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
97 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
98 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
99 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
100 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
101 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
102 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
103 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
104 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
105 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
106 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
107 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
108 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
109 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
110 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
111 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
112 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
113 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
114 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
115 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
116 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
117 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
118 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
119 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
120 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
121 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
122 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
123 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
124 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
125 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
126 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
127 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
128 0x2d02ef8dU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129};
130
Sam Ravnborgce560682006-03-12 23:26:29 +0100131static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100133 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134}
135
Sam Ravnborgce560682006-03-12 23:26:29 +0100136static unsigned long partial_crc32(const char *s, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100138 while (*s)
139 crc = partial_crc32_one(*s++, crc);
140 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141}
142
Sam Ravnborgce560682006-03-12 23:26:29 +0100143static unsigned long crc32(const char *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100145 return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146}
147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148/*----------------------------------------------------------------------*/
149
Sam Ravnborgce560682006-03-12 23:26:29 +0100150static enum symbol_type map_to_ns(enum symbol_type t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151{
Michal Mareke37ddb82011-02-03 23:57:09 +0100152 switch (t) {
153 case SYM_ENUM_CONST:
154 case SYM_NORMAL:
155 case SYM_TYPEDEF:
156 return SYM_NORMAL;
157 case SYM_ENUM:
158 case SYM_STRUCT:
159 case SYM_UNION:
160 return SYM_STRUCT;
161 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100162 return t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163}
164
Michal Marek01762c42011-02-15 15:11:36 +0100165struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100167 unsigned long h = crc32(name) % HASH_BUCKETS;
168 struct symbol *sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Sam Ravnborg78c041532006-03-12 22:59:36 +0100170 for (sym = symtab[h]; sym; sym = sym->hash_next)
Sam Ravnborgce560682006-03-12 23:26:29 +0100171 if (map_to_ns(sym->type) == map_to_ns(ns) &&
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800172 strcmp(name, sym->name) == 0 &&
173 sym->is_declared)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100174 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
Michal Marek01762c42011-02-15 15:11:36 +0100176 if (exact && sym && sym->type != ns)
177 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 return sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179}
180
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800181static int is_unknown_symbol(struct symbol *sym)
182{
183 struct string_list *defn;
184
185 return ((sym->type == SYM_STRUCT ||
186 sym->type == SYM_UNION ||
187 sym->type == SYM_ENUM) &&
188 (defn = sym->defn) && defn->tag == SYM_NORMAL &&
189 strcmp(defn->string, "}") == 0 &&
190 (defn = defn->next) && defn->tag == SYM_NORMAL &&
191 strcmp(defn->string, "UNKNOWN") == 0 &&
192 (defn = defn->next) && defn->tag == SYM_NORMAL &&
193 strcmp(defn->string, "{") == 0);
194}
195
Ladinu Chandrasingheb7ed6982009-09-22 16:43:42 -0700196static struct symbol *__add_symbol(const char *name, enum symbol_type type,
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800197 struct string_list *defn, int is_extern,
198 int is_reference)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100199{
Michal Mareke37ddb82011-02-03 23:57:09 +0100200 unsigned long h;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100201 struct symbol *sym;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800202 enum symbol_status status = STATUS_UNCHANGED;
Michal Mareke37ddb82011-02-03 23:57:09 +0100203 /* The parser adds symbols in the order their declaration completes,
204 * so it is safe to store the value of the previous enum constant in
205 * a static variable.
206 */
207 static int enum_counter;
208 static struct string_list *last_enum_expr;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100209
Michal Mareke37ddb82011-02-03 23:57:09 +0100210 if (type == SYM_ENUM_CONST) {
211 if (defn) {
212 free_list(last_enum_expr, NULL);
213 last_enum_expr = copy_list_range(defn, NULL);
214 enum_counter = 1;
215 } else {
216 struct string_list *expr;
217 char buf[20];
218
219 snprintf(buf, sizeof(buf), "%d", enum_counter++);
220 if (last_enum_expr) {
221 expr = copy_list_range(last_enum_expr, NULL);
222 defn = concat_list(mk_node("("),
223 expr,
224 mk_node(")"),
225 mk_node("+"),
226 mk_node(buf), NULL);
227 } else {
228 defn = mk_node(buf);
229 }
230 }
231 } else if (type == SYM_ENUM) {
232 free_list(last_enum_expr, NULL);
233 last_enum_expr = NULL;
234 enum_counter = 0;
235 if (!name)
236 /* Anonymous enum definition, nothing more to do */
237 return NULL;
238 }
239
240 h = crc32(name) % HASH_BUCKETS;
Sam Ravnborgce560682006-03-12 23:26:29 +0100241 for (sym = symtab[h]; sym; sym = sym->hash_next) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800242 if (map_to_ns(sym->type) == map_to_ns(type) &&
243 strcmp(name, sym->name) == 0) {
244 if (is_reference)
245 /* fall through */ ;
246 else if (sym->type == type &&
247 equal_list(sym->defn, defn)) {
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800248 if (!sym->is_declared && sym->is_override) {
249 print_location();
250 print_type_name(type, name);
251 fprintf(stderr, " modversion is "
252 "unchanged\n");
253 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800254 sym->is_declared = 1;
255 return sym;
256 } else if (!sym->is_declared) {
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800257 if (sym->is_override && flag_preserve) {
258 print_location();
259 fprintf(stderr, "ignoring ");
260 print_type_name(type, name);
261 fprintf(stderr, " modversion change\n");
262 sym->is_declared = 1;
263 return sym;
264 } else {
265 status = is_unknown_symbol(sym) ?
266 STATUS_DEFINED : STATUS_MODIFIED;
267 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800268 } else {
Sam Ravnborg78c041532006-03-12 22:59:36 +0100269 error_with_pos("redefinition of %s", name);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800270 return sym;
271 }
272 break;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100273 }
Sam Ravnborgce560682006-03-12 23:26:29 +0100274 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100275
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800276 if (sym) {
277 struct symbol **psym;
278
279 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
280 if (*psym == sym) {
281 *psym = sym->hash_next;
282 break;
283 }
284 }
285 --nsyms;
286 }
287
Sam Ravnborg78c041532006-03-12 22:59:36 +0100288 sym = xmalloc(sizeof(*sym));
289 sym->name = name;
290 sym->type = type;
291 sym->defn = defn;
292 sym->expansion_trail = NULL;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200293 sym->visited = NULL;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100294 sym->is_extern = is_extern;
295
296 sym->hash_next = symtab[h];
297 symtab[h] = sym;
298
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800299 sym->is_declared = !is_reference;
300 sym->status = status;
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800301 sym->is_override = 0;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800302
Sam Ravnborg78c041532006-03-12 22:59:36 +0100303 if (flag_debug) {
Michal Marek7ec8eda2011-01-18 16:28:06 +0100304 if (symbol_types[type].name)
305 fprintf(debugfile, "Defn for %s %s == <",
306 symbol_types[type].name, name);
307 else
308 fprintf(debugfile, "Defn for type%d %s == <",
309 type, name);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100310 if (is_extern)
311 fputs("extern ", debugfile);
312 print_list(debugfile, defn);
313 fputs(">\n", debugfile);
314 }
315
316 ++nsyms;
317 return sym;
318}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800320struct symbol *add_symbol(const char *name, enum symbol_type type,
321 struct string_list *defn, int is_extern)
322{
323 return __add_symbol(name, type, defn, is_extern, 0);
324}
325
Ladinu Chandrasingheb7ed6982009-09-22 16:43:42 -0700326static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800327 struct string_list *defn, int is_extern)
328{
329 return __add_symbol(name, type, defn, is_extern, 1);
330}
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332/*----------------------------------------------------------------------*/
333
Sam Ravnborgce560682006-03-12 23:26:29 +0100334void free_node(struct string_list *node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100336 free(node->string);
337 free(node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338}
339
Sam Ravnborg78c041532006-03-12 22:59:36 +0100340void free_list(struct string_list *s, struct string_list *e)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100342 while (s != e) {
343 struct string_list *next = s->next;
344 free_node(s);
345 s = next;
346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347}
348
Michal Marek68eb8562011-02-02 23:52:13 +0100349static struct string_list *mk_node(const char *string)
350{
351 struct string_list *newnode;
352
353 newnode = xmalloc(sizeof(*newnode));
354 newnode->string = xstrdup(string);
355 newnode->tag = SYM_NORMAL;
356 newnode->next = NULL;
357
358 return newnode;
359}
360
361static struct string_list *concat_list(struct string_list *start, ...)
362{
363 va_list ap;
364 struct string_list *n, *n2;
365
366 if (!start)
367 return NULL;
368 for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
369 for (n2 = n; n2->next; n2 = n2->next)
370 ;
371 n2->next = start;
372 start = n;
373 }
374 va_end(ap);
375 return start;
376}
377
Sam Ravnborgce560682006-03-12 23:26:29 +0100378struct string_list *copy_node(struct string_list *node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100380 struct string_list *newnode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Sam Ravnborg78c041532006-03-12 22:59:36 +0100382 newnode = xmalloc(sizeof(*newnode));
383 newnode->string = xstrdup(node->string);
384 newnode->tag = node->tag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Sam Ravnborg78c041532006-03-12 22:59:36 +0100386 return newnode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387}
388
Michal Mareke37ddb82011-02-03 23:57:09 +0100389struct string_list *copy_list_range(struct string_list *start,
390 struct string_list *end)
391{
392 struct string_list *res, *n;
393
394 if (start == end)
395 return NULL;
396 n = res = copy_node(start);
397 for (start = start->next; start != end; start = start->next) {
398 n->next = copy_node(start);
399 n = n->next;
400 }
401 n->next = NULL;
402 return res;
403}
404
Sam Ravnborgce560682006-03-12 23:26:29 +0100405static int equal_list(struct string_list *a, struct string_list *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100407 while (a && b) {
408 if (a->tag != b->tag || strcmp(a->string, b->string))
409 return 0;
410 a = a->next;
411 b = b->next;
412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Sam Ravnborg78c041532006-03-12 22:59:36 +0100414 return !a && !b;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415}
416
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800417#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
418
Ladinu Chandrasingheb7ed6982009-09-22 16:43:42 -0700419static struct string_list *read_node(FILE *f)
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800420{
421 char buffer[256];
422 struct string_list node = {
423 .string = buffer,
424 .tag = SYM_NORMAL };
Michal Mareka78f70e2015-12-09 15:08:21 +0100425 int c, in_string = 0;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800426
427 while ((c = fgetc(f)) != EOF) {
Michal Mareka78f70e2015-12-09 15:08:21 +0100428 if (!in_string && c == ' ') {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800429 if (node.string == buffer)
430 continue;
431 break;
Michal Mareka78f70e2015-12-09 15:08:21 +0100432 } else if (c == '"') {
433 in_string = !in_string;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800434 } else if (c == '\n') {
435 if (node.string == buffer)
436 return NULL;
437 ungetc(c, f);
438 break;
439 }
440 if (node.string >= buffer + sizeof(buffer) - 1) {
441 fprintf(stderr, "Token too long\n");
442 exit(1);
443 }
444 *node.string++ = c;
445 }
446 if (node.string == buffer)
447 return NULL;
448 *node.string = 0;
449 node.string = buffer;
450
451 if (node.string[1] == '#') {
Jesper Juhl1ae14702011-07-12 00:32:04 +0200452 size_t n;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800453
Michal Marek7ec8eda2011-01-18 16:28:06 +0100454 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
455 if (node.string[0] == symbol_types[n].n) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800456 node.tag = n;
457 node.string += 2;
458 return copy_node(&node);
459 }
460 }
461 fprintf(stderr, "Unknown type %c\n", node.string[0]);
462 exit(1);
463 }
464 return copy_node(&node);
465}
466
467static void read_reference(FILE *f)
468{
469 while (!feof(f)) {
470 struct string_list *defn = NULL;
471 struct string_list *sym, *def;
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800472 int is_extern = 0, is_override = 0;
473 struct symbol *subsym;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800474
475 sym = read_node(f);
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800476 if (sym && sym->tag == SYM_NORMAL &&
477 !strcmp(sym->string, "override")) {
478 is_override = 1;
479 free_node(sym);
480 sym = read_node(f);
481 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800482 if (!sym)
483 continue;
484 def = read_node(f);
485 if (def && def->tag == SYM_NORMAL &&
486 !strcmp(def->string, "extern")) {
487 is_extern = 1;
488 free_node(def);
489 def = read_node(f);
490 }
491 while (def) {
492 def->next = defn;
493 defn = def;
494 def = read_node(f);
495 }
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800496 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800497 defn, is_extern);
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800498 subsym->is_override = is_override;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800499 free_node(sym);
500 }
501}
502
Sam Ravnborgce560682006-03-12 23:26:29 +0100503static void print_node(FILE * f, struct string_list *list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504{
Michal Marek7ec8eda2011-01-18 16:28:06 +0100505 if (symbol_types[list->tag].n) {
506 putc(symbol_types[list->tag].n, f);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100507 putc('#', f);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100508 }
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200509 fputs(list->string, f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510}
511
Sam Ravnborgce560682006-03-12 23:26:29 +0100512static void print_list(FILE * f, struct string_list *list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100514 struct string_list **e, **b;
515 struct string_list *tmp, **tmp2;
516 int elem = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
Sam Ravnborg78c041532006-03-12 22:59:36 +0100518 if (list == NULL) {
519 fputs("(nil)", f);
520 return;
521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Sam Ravnborg78c041532006-03-12 22:59:36 +0100523 tmp = list;
524 while ((tmp = tmp->next) != NULL)
525 elem++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Sam Ravnborg78c041532006-03-12 22:59:36 +0100527 b = alloca(elem * sizeof(*e));
528 e = b + elem;
529 tmp2 = e - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
Sam Ravnborg78c041532006-03-12 22:59:36 +0100531 (*tmp2--) = list;
532 while ((list = list->next) != NULL)
533 *(tmp2--) = list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Sam Ravnborg78c041532006-03-12 22:59:36 +0100535 while (b != e) {
536 print_node(f, *b++);
537 putc(' ', f);
538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539}
540
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200541static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200543 struct string_list *list = sym->defn;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100544 struct string_list **e, **b;
545 struct string_list *tmp, **tmp2;
546 int elem = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Sam Ravnborg78c041532006-03-12 22:59:36 +0100548 if (!list)
549 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
Sam Ravnborg78c041532006-03-12 22:59:36 +0100551 tmp = list;
552 while ((tmp = tmp->next) != NULL)
553 elem++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Sam Ravnborg78c041532006-03-12 22:59:36 +0100555 b = alloca(elem * sizeof(*e));
556 e = b + elem;
557 tmp2 = e - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
Sam Ravnborg78c041532006-03-12 22:59:36 +0100559 *(tmp2--) = list;
560 while ((list = list->next) != NULL)
561 *(tmp2--) = list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Sam Ravnborg78c041532006-03-12 22:59:36 +0100563 while (b != e) {
564 struct string_list *cur;
565 struct symbol *subsym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Sam Ravnborg78c041532006-03-12 22:59:36 +0100567 cur = *(b++);
568 switch (cur->tag) {
569 case SYM_NORMAL:
570 if (flag_dump_defs)
571 fprintf(debugfile, "%s ", cur->string);
572 crc = partial_crc32(cur->string, crc);
573 crc = partial_crc32_one(' ', crc);
574 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Michal Mareke37ddb82011-02-03 23:57:09 +0100576 case SYM_ENUM_CONST:
Sam Ravnborg78c041532006-03-12 22:59:36 +0100577 case SYM_TYPEDEF:
Michal Marek01762c42011-02-15 15:11:36 +0100578 subsym = find_symbol(cur->string, cur->tag, 0);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800579 /* FIXME: Bad reference files can segfault here. */
Sam Ravnborg78c041532006-03-12 22:59:36 +0100580 if (subsym->expansion_trail) {
581 if (flag_dump_defs)
582 fprintf(debugfile, "%s ", cur->string);
583 crc = partial_crc32(cur->string, crc);
584 crc = partial_crc32_one(' ', crc);
585 } else {
586 subsym->expansion_trail = expansion_trail;
587 expansion_trail = subsym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200588 crc = expand_and_crc_sym(subsym, crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100589 }
590 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Sam Ravnborg78c041532006-03-12 22:59:36 +0100592 case SYM_STRUCT:
593 case SYM_UNION:
594 case SYM_ENUM:
Michal Marek01762c42011-02-15 15:11:36 +0100595 subsym = find_symbol(cur->string, cur->tag, 0);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100596 if (!subsym) {
Michal Marek68eb8562011-02-02 23:52:13 +0100597 struct string_list *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
Sam Ravnborg78c041532006-03-12 22:59:36 +0100599 error_with_pos("expand undefined %s %s",
Michal Marek7ec8eda2011-01-18 16:28:06 +0100600 symbol_types[cur->tag].name,
Sam Ravnborg78c041532006-03-12 22:59:36 +0100601 cur->string);
Michal Marek68eb8562011-02-02 23:52:13 +0100602 n = concat_list(mk_node
603 (symbol_types[cur->tag].name),
604 mk_node(cur->string),
605 mk_node("{"),
606 mk_node("UNKNOWN"),
607 mk_node("}"), NULL);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100608 subsym =
609 add_symbol(cur->string, cur->tag, n, 0);
610 }
611 if (subsym->expansion_trail) {
612 if (flag_dump_defs) {
613 fprintf(debugfile, "%s %s ",
Michal Marek7ec8eda2011-01-18 16:28:06 +0100614 symbol_types[cur->tag].name,
Sam Ravnborg78c041532006-03-12 22:59:36 +0100615 cur->string);
616 }
617
Michal Marek7ec8eda2011-01-18 16:28:06 +0100618 crc = partial_crc32(symbol_types[cur->tag].name,
Sam Ravnborgce560682006-03-12 23:26:29 +0100619 crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100620 crc = partial_crc32_one(' ', crc);
621 crc = partial_crc32(cur->string, crc);
622 crc = partial_crc32_one(' ', crc);
623 } else {
624 subsym->expansion_trail = expansion_trail;
625 expansion_trail = subsym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200626 crc = expand_and_crc_sym(subsym, crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100627 }
628 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200632 {
633 static struct symbol **end = &visited_symbols;
634
635 if (!sym->visited) {
636 *end = sym;
637 end = &sym->visited;
638 sym->visited = (struct symbol *)-1L;
639 }
640 }
641
Sam Ravnborg78c041532006-03-12 22:59:36 +0100642 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643}
644
Sam Ravnborg78c041532006-03-12 22:59:36 +0100645void export_symbol(const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100647 struct symbol *sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Michal Marek01762c42011-02-15 15:11:36 +0100649 sym = find_symbol(name, SYM_NORMAL, 0);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100650 if (!sym)
651 error_with_pos("export undefined symbol %s", name);
652 else {
653 unsigned long crc;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800654 int has_changed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Sam Ravnborg78c041532006-03-12 22:59:36 +0100656 if (flag_dump_defs)
657 fprintf(debugfile, "Export %s == <", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Sam Ravnborg78c041532006-03-12 22:59:36 +0100659 expansion_trail = (struct symbol *)-1L;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800661 sym->expansion_trail = expansion_trail;
662 expansion_trail = sym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200663 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
Sam Ravnborg78c041532006-03-12 22:59:36 +0100665 sym = expansion_trail;
666 while (sym != (struct symbol *)-1L) {
667 struct symbol *n = sym->expansion_trail;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800668
669 if (sym->status != STATUS_UNCHANGED) {
670 if (!has_changed) {
671 print_location();
672 fprintf(stderr, "%s: %s: modversion "
673 "changed because of changes "
674 "in ", flag_preserve ? "error" :
675 "warning", name);
676 } else
677 fprintf(stderr, ", ");
678 print_type_name(sym->type, sym->name);
679 if (sym->status == STATUS_DEFINED)
680 fprintf(stderr, " (became defined)");
681 has_changed = 1;
682 if (flag_preserve)
683 errors++;
684 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100685 sym->expansion_trail = 0;
686 sym = n;
687 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800688 if (has_changed)
689 fprintf(stderr, "\n");
Sam Ravnborg78c041532006-03-12 22:59:36 +0100690
691 if (flag_dump_defs)
692 fputs(">\n", debugfile);
693
Sam Ravnborg2ea03892009-01-14 21:38:20 +0100694 /* Used as a linker script. */
Masahiro Yamada74d93172018-05-09 16:23:46 +0900695 printf(!flag_rel_crcs ? "__crc_%s = 0x%08lx;\n" :
Ard Biesheuvel56067812017-02-03 09:54:05 +0000696 "SECTIONS { .rodata : ALIGN(4) { "
Masahiro Yamada74d93172018-05-09 16:23:46 +0900697 "__crc_%s = .; LONG(0x%08lx); } }\n",
698 name, crc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700}
701
702/*----------------------------------------------------------------------*/
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800703
704static void print_location(void)
705{
706 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
707}
708
709static void print_type_name(enum symbol_type type, const char *name)
710{
Michal Marek7ec8eda2011-01-18 16:28:06 +0100711 if (symbol_types[type].name)
712 fprintf(stderr, "%s %s", symbol_types[type].name, name);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800713 else
714 fprintf(stderr, "%s", name);
715}
716
Sam Ravnborg78c041532006-03-12 22:59:36 +0100717void error_with_pos(const char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100719 va_list args;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Sam Ravnborg78c041532006-03-12 22:59:36 +0100721 if (flag_warnings) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800722 print_location();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Sam Ravnborg78c041532006-03-12 22:59:36 +0100724 va_start(args, fmt);
725 vfprintf(stderr, fmt, args);
726 va_end(args);
727 putc('\n', stderr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
Sam Ravnborg78c041532006-03-12 22:59:36 +0100729 errors++;
730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
732
Sam Ravnborgce560682006-03-12 23:26:29 +0100733static void genksyms_usage(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
Ard Biesheuvel56067812017-02-03 09:54:05 +0000735 fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736#ifdef __GNU_LIBRARY__
James Hogand70f82a2013-03-18 19:38:56 +1030737 " -s, --symbol-prefix Select symbol prefix\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 " -d, --debug Increment the debug level (repeatable)\n"
739 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800740 " -r, --reference file Read reference symbols from a file\n"
741 " -T, --dump-types file Dump expanded types into file\n"
742 " -p, --preserve Preserve reference modversions or fail\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 " -w, --warnings Enable warnings\n"
744 " -q, --quiet Disable warnings (default)\n"
745 " -h, --help Print this message\n"
746 " -V, --version Print the release version\n"
Ard Biesheuvel56067812017-02-03 09:54:05 +0000747 " -R, --relative-crc Emit section relative symbol CRCs\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100748#else /* __GNU_LIBRARY__ */
James Hogand70f82a2013-03-18 19:38:56 +1030749 " -s Select symbol prefix\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100750 " -d Increment the debug level (repeatable)\n"
751 " -D Dump expanded symbol defs (for debugging only)\n"
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800752 " -r file Read reference symbols from a file\n"
753 " -T file Dump expanded types into file\n"
754 " -p Preserve reference modversions or fail\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100755 " -w Enable warnings\n"
756 " -q Disable warnings (default)\n"
757 " -h Print this message\n"
758 " -V Print the release version\n"
Ard Biesheuvel56067812017-02-03 09:54:05 +0000759 " -R Emit section relative symbol CRCs\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100760#endif /* __GNU_LIBRARY__ */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 , stderr);
762}
763
Sam Ravnborg78c041532006-03-12 22:59:36 +0100764int main(int argc, char **argv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800766 FILE *dumpfile = NULL, *ref_file = NULL;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100767 int o;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769#ifdef __GNU_LIBRARY__
Sam Ravnborg78c041532006-03-12 22:59:36 +0100770 struct option long_opts[] = {
Sam Ravnborg78c041532006-03-12 22:59:36 +0100771 {"debug", 0, 0, 'd'},
772 {"warnings", 0, 0, 'w'},
773 {"quiet", 0, 0, 'q'},
774 {"dump", 0, 0, 'D'},
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800775 {"reference", 1, 0, 'r'},
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200776 {"dump-types", 1, 0, 'T'},
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800777 {"preserve", 0, 0, 'p'},
Sam Ravnborg78c041532006-03-12 22:59:36 +0100778 {"version", 0, 0, 'V'},
779 {"help", 0, 0, 'h'},
Ard Biesheuvel56067812017-02-03 09:54:05 +0000780 {"relative-crc", 0, 0, 'R'},
Sam Ravnborg78c041532006-03-12 22:59:36 +0100781 {0, 0, 0, 0}
782 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Ard Biesheuvel56067812017-02-03 09:54:05 +0000784 while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
Sam Ravnborg78c041532006-03-12 22:59:36 +0100785 &long_opts[0], NULL)) != EOF)
786#else /* __GNU_LIBRARY__ */
Ard Biesheuvel56067812017-02-03 09:54:05 +0000787 while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100788#endif /* __GNU_LIBRARY__ */
789 switch (o) {
Sam Ravnborg78c041532006-03-12 22:59:36 +0100790 case 'd':
791 flag_debug++;
792 break;
793 case 'w':
794 flag_warnings = 1;
795 break;
796 case 'q':
797 flag_warnings = 0;
798 break;
799 case 'V':
800 fputs("genksyms version 2.5.60\n", stderr);
801 break;
802 case 'D':
803 flag_dump_defs = 1;
804 break;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800805 case 'r':
806 flag_reference = 1;
807 ref_file = fopen(optarg, "r");
808 if (!ref_file) {
809 perror(optarg);
810 return 1;
811 }
812 break;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200813 case 'T':
814 flag_dump_types = 1;
815 dumpfile = fopen(optarg, "w");
816 if (!dumpfile) {
817 perror(optarg);
818 return 1;
819 }
820 break;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800821 case 'p':
822 flag_preserve = 1;
823 break;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100824 case 'h':
825 genksyms_usage();
826 return 0;
Ard Biesheuvel56067812017-02-03 09:54:05 +0000827 case 'R':
828 flag_rel_crcs = 1;
829 break;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100830 default:
831 genksyms_usage();
832 return 1;
833 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100834 {
835 extern int yydebug;
836 extern int yy_flex_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Sam Ravnborg78c041532006-03-12 22:59:36 +0100838 yydebug = (flag_debug > 1);
839 yy_flex_debug = (flag_debug > 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Sam Ravnborg78c041532006-03-12 22:59:36 +0100841 debugfile = stderr;
842 /* setlinebuf(debugfile); */
843 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
Alexander Beregalovc64152b2010-01-07 05:22:41 +0300845 if (flag_reference) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800846 read_reference(ref_file);
Alexander Beregalovc64152b2010-01-07 05:22:41 +0300847 fclose(ref_file);
848 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800849
Sam Ravnborg78c041532006-03-12 22:59:36 +0100850 yyparse();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200852 if (flag_dump_types && visited_symbols) {
853 while (visited_symbols != (struct symbol *)-1L) {
854 struct symbol *sym = visited_symbols;
855
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800856 if (sym->is_override)
857 fputs("override ", dumpfile);
Michal Marek7ec8eda2011-01-18 16:28:06 +0100858 if (symbol_types[sym->type].n) {
859 putc(symbol_types[sym->type].n, dumpfile);
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200860 putc('#', dumpfile);
861 }
862 fputs(sym->name, dumpfile);
863 putc(' ', dumpfile);
Andreas Gruenbacher3b40d382008-07-21 04:28:25 +0200864 if (sym->is_extern)
865 fputs("extern ", dumpfile);
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200866 print_list(dumpfile, sym->defn);
867 putc('\n', dumpfile);
868
869 visited_symbols = sym->visited;
870 sym->visited = NULL;
871 }
872 }
873
Sam Ravnborg78c041532006-03-12 22:59:36 +0100874 if (flag_debug) {
875 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
876 nsyms, HASH_BUCKETS,
877 (double)nsyms / (double)HASH_BUCKETS);
878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
Maxim Zhukov4deaaa42016-04-12 23:54:59 +0300880 if (dumpfile)
881 fclose(dumpfile);
882
Sam Ravnborg78c041532006-03-12 22:59:36 +0100883 return errors != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884}