blob: c9235d8340f1e7ba33eacfaee94642c18f5fd211 [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;
Sam Ravnborgce560682006-03-12 23:26:29 +010048static 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"},
Michal Mareke37ddb82011-02-03 23:57:09 +010065 [SYM_ENUM_CONST] = {'E', "enum constant"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070066};
67
Sam Ravnborgce560682006-03-12 23:26:29 +010068static int equal_list(struct string_list *a, struct string_list *b);
69static void print_list(FILE * f, struct string_list *list);
Michal Marek68eb8562011-02-02 23:52:13 +010070static struct string_list *concat_list(struct string_list *start, ...);
71static struct string_list *mk_node(const char *string);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -080072static void print_location(void);
73static void print_type_name(enum symbol_type type, const char *name);
Sam Ravnborgce560682006-03-12 23:26:29 +010074
Linus Torvalds1da177e2005-04-16 15:20:36 -070075/*----------------------------------------------------------------------*/
76
Sam Ravnborg78c041532006-03-12 22:59:36 +010077static const unsigned int crctab32[] = {
78 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
79 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
80 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
81 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
82 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
83 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
84 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
85 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
86 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
87 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
88 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
89 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
90 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
91 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
92 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
93 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
94 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
95 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
96 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
97 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
98 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
99 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
100 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
101 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
102 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
103 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
104 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
105 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
106 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
107 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
108 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
109 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
110 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
111 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
112 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
113 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
114 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
115 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
116 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
117 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
118 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
119 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
120 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
121 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
122 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
123 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
124 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
125 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
126 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
127 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
128 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
129 0x2d02ef8dU
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130};
131
Sam Ravnborgce560682006-03-12 23:26:29 +0100132static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100134 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135}
136
Sam Ravnborgce560682006-03-12 23:26:29 +0100137static unsigned long partial_crc32(const char *s, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100139 while (*s)
140 crc = partial_crc32_one(*s++, crc);
141 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142}
143
Sam Ravnborgce560682006-03-12 23:26:29 +0100144static unsigned long crc32(const char *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100146 return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147}
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149/*----------------------------------------------------------------------*/
150
Sam Ravnborgce560682006-03-12 23:26:29 +0100151static enum symbol_type map_to_ns(enum symbol_type t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152{
Michal Mareke37ddb82011-02-03 23:57:09 +0100153 switch (t) {
154 case SYM_ENUM_CONST:
155 case SYM_NORMAL:
156 case SYM_TYPEDEF:
157 return SYM_NORMAL;
158 case SYM_ENUM:
159 case SYM_STRUCT:
160 case SYM_UNION:
161 return SYM_STRUCT;
162 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100163 return t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164}
165
Michal Marek01762c42011-02-15 15:11:36 +0100166struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100168 unsigned long h = crc32(name) % HASH_BUCKETS;
169 struct symbol *sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
Sam Ravnborg78c041532006-03-12 22:59:36 +0100171 for (sym = symtab[h]; sym; sym = sym->hash_next)
Sam Ravnborgce560682006-03-12 23:26:29 +0100172 if (map_to_ns(sym->type) == map_to_ns(ns) &&
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800173 strcmp(name, sym->name) == 0 &&
174 sym->is_declared)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100175 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Michal Marek01762c42011-02-15 15:11:36 +0100177 if (exact && sym && sym->type != ns)
178 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 return sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180}
181
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800182static int is_unknown_symbol(struct symbol *sym)
183{
184 struct string_list *defn;
185
186 return ((sym->type == SYM_STRUCT ||
187 sym->type == SYM_UNION ||
188 sym->type == SYM_ENUM) &&
189 (defn = sym->defn) && defn->tag == SYM_NORMAL &&
190 strcmp(defn->string, "}") == 0 &&
191 (defn = defn->next) && defn->tag == SYM_NORMAL &&
192 strcmp(defn->string, "UNKNOWN") == 0 &&
193 (defn = defn->next) && defn->tag == SYM_NORMAL &&
194 strcmp(defn->string, "{") == 0);
195}
196
Ladinu Chandrasingheb7ed6982009-09-22 16:43:42 -0700197static struct symbol *__add_symbol(const char *name, enum symbol_type type,
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800198 struct string_list *defn, int is_extern,
199 int is_reference)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100200{
Michal Mareke37ddb82011-02-03 23:57:09 +0100201 unsigned long h;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100202 struct symbol *sym;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800203 enum symbol_status status = STATUS_UNCHANGED;
Michal Mareke37ddb82011-02-03 23:57:09 +0100204 /* The parser adds symbols in the order their declaration completes,
205 * so it is safe to store the value of the previous enum constant in
206 * a static variable.
207 */
208 static int enum_counter;
209 static struct string_list *last_enum_expr;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100210
Michal Mareke37ddb82011-02-03 23:57:09 +0100211 if (type == SYM_ENUM_CONST) {
212 if (defn) {
213 free_list(last_enum_expr, NULL);
214 last_enum_expr = copy_list_range(defn, NULL);
215 enum_counter = 1;
216 } else {
217 struct string_list *expr;
218 char buf[20];
219
220 snprintf(buf, sizeof(buf), "%d", enum_counter++);
221 if (last_enum_expr) {
222 expr = copy_list_range(last_enum_expr, NULL);
223 defn = concat_list(mk_node("("),
224 expr,
225 mk_node(")"),
226 mk_node("+"),
227 mk_node(buf), NULL);
228 } else {
229 defn = mk_node(buf);
230 }
231 }
232 } else if (type == SYM_ENUM) {
233 free_list(last_enum_expr, NULL);
234 last_enum_expr = NULL;
235 enum_counter = 0;
236 if (!name)
237 /* Anonymous enum definition, nothing more to do */
238 return NULL;
239 }
240
241 h = crc32(name) % HASH_BUCKETS;
Sam Ravnborgce560682006-03-12 23:26:29 +0100242 for (sym = symtab[h]; sym; sym = sym->hash_next) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800243 if (map_to_ns(sym->type) == map_to_ns(type) &&
244 strcmp(name, sym->name) == 0) {
245 if (is_reference)
246 /* fall through */ ;
247 else if (sym->type == type &&
248 equal_list(sym->defn, defn)) {
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800249 if (!sym->is_declared && sym->is_override) {
250 print_location();
251 print_type_name(type, name);
252 fprintf(stderr, " modversion is "
253 "unchanged\n");
254 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800255 sym->is_declared = 1;
256 return sym;
257 } else if (!sym->is_declared) {
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800258 if (sym->is_override && flag_preserve) {
259 print_location();
260 fprintf(stderr, "ignoring ");
261 print_type_name(type, name);
262 fprintf(stderr, " modversion change\n");
263 sym->is_declared = 1;
264 return sym;
265 } else {
266 status = is_unknown_symbol(sym) ?
267 STATUS_DEFINED : STATUS_MODIFIED;
268 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800269 } else {
Sam Ravnborg78c041532006-03-12 22:59:36 +0100270 error_with_pos("redefinition of %s", name);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800271 return sym;
272 }
273 break;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100274 }
Sam Ravnborgce560682006-03-12 23:26:29 +0100275 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100276
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800277 if (sym) {
278 struct symbol **psym;
279
280 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
281 if (*psym == sym) {
282 *psym = sym->hash_next;
283 break;
284 }
285 }
286 --nsyms;
287 }
288
Sam Ravnborg78c041532006-03-12 22:59:36 +0100289 sym = xmalloc(sizeof(*sym));
290 sym->name = name;
291 sym->type = type;
292 sym->defn = defn;
293 sym->expansion_trail = NULL;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200294 sym->visited = NULL;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100295 sym->is_extern = is_extern;
296
297 sym->hash_next = symtab[h];
298 symtab[h] = sym;
299
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800300 sym->is_declared = !is_reference;
301 sym->status = status;
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800302 sym->is_override = 0;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800303
Sam Ravnborg78c041532006-03-12 22:59:36 +0100304 if (flag_debug) {
Michal Marek7ec8eda2011-01-18 16:28:06 +0100305 if (symbol_types[type].name)
306 fprintf(debugfile, "Defn for %s %s == <",
307 symbol_types[type].name, name);
308 else
309 fprintf(debugfile, "Defn for type%d %s == <",
310 type, name);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100311 if (is_extern)
312 fputs("extern ", debugfile);
313 print_list(debugfile, defn);
314 fputs(">\n", debugfile);
315 }
316
317 ++nsyms;
318 return sym;
319}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800321struct symbol *add_symbol(const char *name, enum symbol_type type,
322 struct string_list *defn, int is_extern)
323{
324 return __add_symbol(name, type, defn, is_extern, 0);
325}
326
Ladinu Chandrasingheb7ed6982009-09-22 16:43:42 -0700327static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800328 struct string_list *defn, int is_extern)
329{
330 return __add_symbol(name, type, defn, is_extern, 1);
331}
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333/*----------------------------------------------------------------------*/
334
Sam Ravnborgce560682006-03-12 23:26:29 +0100335void free_node(struct string_list *node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100337 free(node->string);
338 free(node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339}
340
Sam Ravnborg78c041532006-03-12 22:59:36 +0100341void free_list(struct string_list *s, struct string_list *e)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100343 while (s != e) {
344 struct string_list *next = s->next;
345 free_node(s);
346 s = next;
347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348}
349
Michal Marek68eb8562011-02-02 23:52:13 +0100350static struct string_list *mk_node(const char *string)
351{
352 struct string_list *newnode;
353
354 newnode = xmalloc(sizeof(*newnode));
355 newnode->string = xstrdup(string);
356 newnode->tag = SYM_NORMAL;
357 newnode->next = NULL;
358
359 return newnode;
360}
361
362static struct string_list *concat_list(struct string_list *start, ...)
363{
364 va_list ap;
365 struct string_list *n, *n2;
366
367 if (!start)
368 return NULL;
369 for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
370 for (n2 = n; n2->next; n2 = n2->next)
371 ;
372 n2->next = start;
373 start = n;
374 }
375 va_end(ap);
376 return start;
377}
378
Sam Ravnborgce560682006-03-12 23:26:29 +0100379struct string_list *copy_node(struct string_list *node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100381 struct string_list *newnode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Sam Ravnborg78c041532006-03-12 22:59:36 +0100383 newnode = xmalloc(sizeof(*newnode));
384 newnode->string = xstrdup(node->string);
385 newnode->tag = node->tag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
Sam Ravnborg78c041532006-03-12 22:59:36 +0100387 return newnode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388}
389
Michal Mareke37ddb82011-02-03 23:57:09 +0100390struct string_list *copy_list_range(struct string_list *start,
391 struct string_list *end)
392{
393 struct string_list *res, *n;
394
395 if (start == end)
396 return NULL;
397 n = res = copy_node(start);
398 for (start = start->next; start != end; start = start->next) {
399 n->next = copy_node(start);
400 n = n->next;
401 }
402 n->next = NULL;
403 return res;
404}
405
Sam Ravnborgce560682006-03-12 23:26:29 +0100406static int equal_list(struct string_list *a, struct string_list *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100408 while (a && b) {
409 if (a->tag != b->tag || strcmp(a->string, b->string))
410 return 0;
411 a = a->next;
412 b = b->next;
413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Sam Ravnborg78c041532006-03-12 22:59:36 +0100415 return !a && !b;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416}
417
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800418#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
419
Ladinu Chandrasingheb7ed6982009-09-22 16:43:42 -0700420static struct string_list *read_node(FILE *f)
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800421{
422 char buffer[256];
423 struct string_list node = {
424 .string = buffer,
425 .tag = SYM_NORMAL };
Michal Mareka78f70e2015-12-09 15:08:21 +0100426 int c, in_string = 0;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800427
428 while ((c = fgetc(f)) != EOF) {
Michal Mareka78f70e2015-12-09 15:08:21 +0100429 if (!in_string && c == ' ') {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800430 if (node.string == buffer)
431 continue;
432 break;
Michal Mareka78f70e2015-12-09 15:08:21 +0100433 } else if (c == '"') {
434 in_string = !in_string;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800435 } else if (c == '\n') {
436 if (node.string == buffer)
437 return NULL;
438 ungetc(c, f);
439 break;
440 }
441 if (node.string >= buffer + sizeof(buffer) - 1) {
442 fprintf(stderr, "Token too long\n");
443 exit(1);
444 }
445 *node.string++ = c;
446 }
447 if (node.string == buffer)
448 return NULL;
449 *node.string = 0;
450 node.string = buffer;
451
452 if (node.string[1] == '#') {
Jesper Juhl1ae14702011-07-12 00:32:04 +0200453 size_t n;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800454
Michal Marek7ec8eda2011-01-18 16:28:06 +0100455 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
456 if (node.string[0] == symbol_types[n].n) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800457 node.tag = n;
458 node.string += 2;
459 return copy_node(&node);
460 }
461 }
462 fprintf(stderr, "Unknown type %c\n", node.string[0]);
463 exit(1);
464 }
465 return copy_node(&node);
466}
467
468static void read_reference(FILE *f)
469{
470 while (!feof(f)) {
471 struct string_list *defn = NULL;
472 struct string_list *sym, *def;
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800473 int is_extern = 0, is_override = 0;
474 struct symbol *subsym;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800475
476 sym = read_node(f);
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800477 if (sym && sym->tag == SYM_NORMAL &&
478 !strcmp(sym->string, "override")) {
479 is_override = 1;
480 free_node(sym);
481 sym = read_node(f);
482 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800483 if (!sym)
484 continue;
485 def = read_node(f);
486 if (def && def->tag == SYM_NORMAL &&
487 !strcmp(def->string, "extern")) {
488 is_extern = 1;
489 free_node(def);
490 def = read_node(f);
491 }
492 while (def) {
493 def->next = defn;
494 defn = def;
495 def = read_node(f);
496 }
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800497 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800498 defn, is_extern);
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800499 subsym->is_override = is_override;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800500 free_node(sym);
501 }
502}
503
Sam Ravnborgce560682006-03-12 23:26:29 +0100504static void print_node(FILE * f, struct string_list *list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505{
Michal Marek7ec8eda2011-01-18 16:28:06 +0100506 if (symbol_types[list->tag].n) {
507 putc(symbol_types[list->tag].n, f);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100508 putc('#', f);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100509 }
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200510 fputs(list->string, f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511}
512
Sam Ravnborgce560682006-03-12 23:26:29 +0100513static void print_list(FILE * f, struct string_list *list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100515 struct string_list **e, **b;
516 struct string_list *tmp, **tmp2;
517 int elem = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
Sam Ravnborg78c041532006-03-12 22:59:36 +0100519 if (list == NULL) {
520 fputs("(nil)", f);
521 return;
522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Sam Ravnborg78c041532006-03-12 22:59:36 +0100524 tmp = list;
525 while ((tmp = tmp->next) != NULL)
526 elem++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Sam Ravnborg78c041532006-03-12 22:59:36 +0100528 b = alloca(elem * sizeof(*e));
529 e = b + elem;
530 tmp2 = e - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Sam Ravnborg78c041532006-03-12 22:59:36 +0100532 (*tmp2--) = list;
533 while ((list = list->next) != NULL)
534 *(tmp2--) = list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
Sam Ravnborg78c041532006-03-12 22:59:36 +0100536 while (b != e) {
537 print_node(f, *b++);
538 putc(' ', f);
539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540}
541
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200542static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543{
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200544 struct string_list *list = sym->defn;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100545 struct string_list **e, **b;
546 struct string_list *tmp, **tmp2;
547 int elem = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Sam Ravnborg78c041532006-03-12 22:59:36 +0100549 if (!list)
550 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Sam Ravnborg78c041532006-03-12 22:59:36 +0100552 tmp = list;
553 while ((tmp = tmp->next) != NULL)
554 elem++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Sam Ravnborg78c041532006-03-12 22:59:36 +0100556 b = alloca(elem * sizeof(*e));
557 e = b + elem;
558 tmp2 = e - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
Sam Ravnborg78c041532006-03-12 22:59:36 +0100560 *(tmp2--) = list;
561 while ((list = list->next) != NULL)
562 *(tmp2--) = list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
Sam Ravnborg78c041532006-03-12 22:59:36 +0100564 while (b != e) {
565 struct string_list *cur;
566 struct symbol *subsym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Sam Ravnborg78c041532006-03-12 22:59:36 +0100568 cur = *(b++);
569 switch (cur->tag) {
570 case SYM_NORMAL:
571 if (flag_dump_defs)
572 fprintf(debugfile, "%s ", cur->string);
573 crc = partial_crc32(cur->string, crc);
574 crc = partial_crc32_one(' ', crc);
575 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Michal Mareke37ddb82011-02-03 23:57:09 +0100577 case SYM_ENUM_CONST:
Sam Ravnborg78c041532006-03-12 22:59:36 +0100578 case SYM_TYPEDEF:
Michal Marek01762c42011-02-15 15:11:36 +0100579 subsym = find_symbol(cur->string, cur->tag, 0);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800580 /* FIXME: Bad reference files can segfault here. */
Sam Ravnborg78c041532006-03-12 22:59:36 +0100581 if (subsym->expansion_trail) {
582 if (flag_dump_defs)
583 fprintf(debugfile, "%s ", cur->string);
584 crc = partial_crc32(cur->string, crc);
585 crc = partial_crc32_one(' ', crc);
586 } else {
587 subsym->expansion_trail = expansion_trail;
588 expansion_trail = subsym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200589 crc = expand_and_crc_sym(subsym, crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100590 }
591 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592
Sam Ravnborg78c041532006-03-12 22:59:36 +0100593 case SYM_STRUCT:
594 case SYM_UNION:
595 case SYM_ENUM:
Michal Marek01762c42011-02-15 15:11:36 +0100596 subsym = find_symbol(cur->string, cur->tag, 0);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100597 if (!subsym) {
Michal Marek68eb8562011-02-02 23:52:13 +0100598 struct string_list *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Sam Ravnborg78c041532006-03-12 22:59:36 +0100600 error_with_pos("expand undefined %s %s",
Michal Marek7ec8eda2011-01-18 16:28:06 +0100601 symbol_types[cur->tag].name,
Sam Ravnborg78c041532006-03-12 22:59:36 +0100602 cur->string);
Michal Marek68eb8562011-02-02 23:52:13 +0100603 n = concat_list(mk_node
604 (symbol_types[cur->tag].name),
605 mk_node(cur->string),
606 mk_node("{"),
607 mk_node("UNKNOWN"),
608 mk_node("}"), NULL);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100609 subsym =
610 add_symbol(cur->string, cur->tag, n, 0);
611 }
612 if (subsym->expansion_trail) {
613 if (flag_dump_defs) {
614 fprintf(debugfile, "%s %s ",
Michal Marek7ec8eda2011-01-18 16:28:06 +0100615 symbol_types[cur->tag].name,
Sam Ravnborg78c041532006-03-12 22:59:36 +0100616 cur->string);
617 }
618
Michal Marek7ec8eda2011-01-18 16:28:06 +0100619 crc = partial_crc32(symbol_types[cur->tag].name,
Sam Ravnborgce560682006-03-12 23:26:29 +0100620 crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100621 crc = partial_crc32_one(' ', crc);
622 crc = partial_crc32(cur->string, crc);
623 crc = partial_crc32_one(' ', crc);
624 } else {
625 subsym->expansion_trail = expansion_trail;
626 expansion_trail = subsym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200627 crc = expand_and_crc_sym(subsym, crc);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100628 }
629 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200633 {
634 static struct symbol **end = &visited_symbols;
635
636 if (!sym->visited) {
637 *end = sym;
638 end = &sym->visited;
639 sym->visited = (struct symbol *)-1L;
640 }
641 }
642
Sam Ravnborg78c041532006-03-12 22:59:36 +0100643 return crc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644}
645
Sam Ravnborg78c041532006-03-12 22:59:36 +0100646void export_symbol(const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100648 struct symbol *sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Michal Marek01762c42011-02-15 15:11:36 +0100650 sym = find_symbol(name, SYM_NORMAL, 0);
Sam Ravnborg78c041532006-03-12 22:59:36 +0100651 if (!sym)
652 error_with_pos("export undefined symbol %s", name);
653 else {
654 unsigned long crc;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800655 int has_changed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Sam Ravnborg78c041532006-03-12 22:59:36 +0100657 if (flag_dump_defs)
658 fprintf(debugfile, "Export %s == <", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Sam Ravnborg78c041532006-03-12 22:59:36 +0100660 expansion_trail = (struct symbol *)-1L;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800662 sym->expansion_trail = expansion_trail;
663 expansion_trail = sym;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200664 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Sam Ravnborg78c041532006-03-12 22:59:36 +0100666 sym = expansion_trail;
667 while (sym != (struct symbol *)-1L) {
668 struct symbol *n = sym->expansion_trail;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800669
670 if (sym->status != STATUS_UNCHANGED) {
671 if (!has_changed) {
672 print_location();
673 fprintf(stderr, "%s: %s: modversion "
674 "changed because of changes "
675 "in ", flag_preserve ? "error" :
676 "warning", name);
677 } else
678 fprintf(stderr, ", ");
679 print_type_name(sym->type, sym->name);
680 if (sym->status == STATUS_DEFINED)
681 fprintf(stderr, " (became defined)");
682 has_changed = 1;
683 if (flag_preserve)
684 errors++;
685 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100686 sym->expansion_trail = 0;
687 sym = n;
688 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800689 if (has_changed)
690 fprintf(stderr, "\n");
Sam Ravnborg78c041532006-03-12 22:59:36 +0100691
692 if (flag_dump_defs)
693 fputs(">\n", debugfile);
694
Sam Ravnborg2ea03892009-01-14 21:38:20 +0100695 /* Used as a linker script. */
Ard Biesheuvel56067812017-02-03 09:54:05 +0000696 printf(!flag_rel_crcs ? "%s__crc_%s = 0x%08lx;\n" :
697 "SECTIONS { .rodata : ALIGN(4) { "
698 "%s__crc_%s = .; LONG(0x%08lx); } }\n",
699 mod_prefix, name, crc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701}
702
703/*----------------------------------------------------------------------*/
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800704
705static void print_location(void)
706{
707 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
708}
709
710static void print_type_name(enum symbol_type type, const char *name)
711{
Michal Marek7ec8eda2011-01-18 16:28:06 +0100712 if (symbol_types[type].name)
713 fprintf(stderr, "%s %s", symbol_types[type].name, name);
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800714 else
715 fprintf(stderr, "%s", name);
716}
717
Sam Ravnborg78c041532006-03-12 22:59:36 +0100718void error_with_pos(const char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
Sam Ravnborg78c041532006-03-12 22:59:36 +0100720 va_list args;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
Sam Ravnborg78c041532006-03-12 22:59:36 +0100722 if (flag_warnings) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800723 print_location();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Sam Ravnborg78c041532006-03-12 22:59:36 +0100725 va_start(args, fmt);
726 vfprintf(stderr, fmt, args);
727 va_end(args);
728 putc('\n', stderr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Sam Ravnborg78c041532006-03-12 22:59:36 +0100730 errors++;
731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732}
733
Sam Ravnborgce560682006-03-12 23:26:29 +0100734static void genksyms_usage(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
Ard Biesheuvel56067812017-02-03 09:54:05 +0000736 fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737#ifdef __GNU_LIBRARY__
James Hogand70f82a2013-03-18 19:38:56 +1030738 " -s, --symbol-prefix Select symbol prefix\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 " -d, --debug Increment the debug level (repeatable)\n"
740 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800741 " -r, --reference file Read reference symbols from a file\n"
742 " -T, --dump-types file Dump expanded types into file\n"
743 " -p, --preserve Preserve reference modversions or fail\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 " -w, --warnings Enable warnings\n"
745 " -q, --quiet Disable warnings (default)\n"
746 " -h, --help Print this message\n"
747 " -V, --version Print the release version\n"
Ard Biesheuvel56067812017-02-03 09:54:05 +0000748 " -R, --relative-crc Emit section relative symbol CRCs\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100749#else /* __GNU_LIBRARY__ */
James Hogand70f82a2013-03-18 19:38:56 +1030750 " -s Select symbol prefix\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100751 " -d Increment the debug level (repeatable)\n"
752 " -D Dump expanded symbol defs (for debugging only)\n"
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800753 " -r file Read reference symbols from a file\n"
754 " -T file Dump expanded types into file\n"
755 " -p Preserve reference modversions or fail\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100756 " -w Enable warnings\n"
757 " -q Disable warnings (default)\n"
758 " -h Print this message\n"
759 " -V Print the release version\n"
Ard Biesheuvel56067812017-02-03 09:54:05 +0000760 " -R Emit section relative symbol CRCs\n"
Sam Ravnborg78c041532006-03-12 22:59:36 +0100761#endif /* __GNU_LIBRARY__ */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 , stderr);
763}
764
Sam Ravnborg78c041532006-03-12 22:59:36 +0100765int main(int argc, char **argv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800767 FILE *dumpfile = NULL, *ref_file = NULL;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100768 int o;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
770#ifdef __GNU_LIBRARY__
Sam Ravnborg78c041532006-03-12 22:59:36 +0100771 struct option long_opts[] = {
James Hogand70f82a2013-03-18 19:38:56 +1030772 {"symbol-prefix", 1, 0, 's'},
Sam Ravnborg78c041532006-03-12 22:59:36 +0100773 {"debug", 0, 0, 'd'},
774 {"warnings", 0, 0, 'w'},
775 {"quiet", 0, 0, 'q'},
776 {"dump", 0, 0, 'D'},
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800777 {"reference", 1, 0, 'r'},
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200778 {"dump-types", 1, 0, 'T'},
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800779 {"preserve", 0, 0, 'p'},
Sam Ravnborg78c041532006-03-12 22:59:36 +0100780 {"version", 0, 0, 'V'},
781 {"help", 0, 0, 'h'},
Ard Biesheuvel56067812017-02-03 09:54:05 +0000782 {"relative-crc", 0, 0, 'R'},
Sam Ravnborg78c041532006-03-12 22:59:36 +0100783 {0, 0, 0, 0}
784 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Ard Biesheuvel56067812017-02-03 09:54:05 +0000786 while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
Sam Ravnborg78c041532006-03-12 22:59:36 +0100787 &long_opts[0], NULL)) != EOF)
788#else /* __GNU_LIBRARY__ */
Ard Biesheuvel56067812017-02-03 09:54:05 +0000789 while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
Sam Ravnborg78c041532006-03-12 22:59:36 +0100790#endif /* __GNU_LIBRARY__ */
791 switch (o) {
James Hogand70f82a2013-03-18 19:38:56 +1030792 case 's':
793 mod_prefix = optarg;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100794 break;
795 case 'd':
796 flag_debug++;
797 break;
798 case 'w':
799 flag_warnings = 1;
800 break;
801 case 'q':
802 flag_warnings = 0;
803 break;
804 case 'V':
805 fputs("genksyms version 2.5.60\n", stderr);
806 break;
807 case 'D':
808 flag_dump_defs = 1;
809 break;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800810 case 'r':
811 flag_reference = 1;
812 ref_file = fopen(optarg, "r");
813 if (!ref_file) {
814 perror(optarg);
815 return 1;
816 }
817 break;
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200818 case 'T':
819 flag_dump_types = 1;
820 dumpfile = fopen(optarg, "w");
821 if (!dumpfile) {
822 perror(optarg);
823 return 1;
824 }
825 break;
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800826 case 'p':
827 flag_preserve = 1;
828 break;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100829 case 'h':
830 genksyms_usage();
831 return 0;
Ard Biesheuvel56067812017-02-03 09:54:05 +0000832 case 'R':
833 flag_rel_crcs = 1;
834 break;
Sam Ravnborg78c041532006-03-12 22:59:36 +0100835 default:
836 genksyms_usage();
837 return 1;
838 }
Sam Ravnborg78c041532006-03-12 22:59:36 +0100839 {
840 extern int yydebug;
841 extern int yy_flex_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
Sam Ravnborg78c041532006-03-12 22:59:36 +0100843 yydebug = (flag_debug > 1);
844 yy_flex_debug = (flag_debug > 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Sam Ravnborg78c041532006-03-12 22:59:36 +0100846 debugfile = stderr;
847 /* setlinebuf(debugfile); */
848 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
Alexander Beregalovc64152b2010-01-07 05:22:41 +0300850 if (flag_reference) {
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800851 read_reference(ref_file);
Alexander Beregalovc64152b2010-01-07 05:22:41 +0300852 fclose(ref_file);
853 }
Andreas Gruenbacher64e6c1e2008-12-01 14:21:01 -0800854
Sam Ravnborg78c041532006-03-12 22:59:36 +0100855 yyparse();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200857 if (flag_dump_types && visited_symbols) {
858 while (visited_symbols != (struct symbol *)-1L) {
859 struct symbol *sym = visited_symbols;
860
Andreas Gruenbacher5dae9a52008-12-01 14:21:03 -0800861 if (sym->is_override)
862 fputs("override ", dumpfile);
Michal Marek7ec8eda2011-01-18 16:28:06 +0100863 if (symbol_types[sym->type].n) {
864 putc(symbol_types[sym->type].n, dumpfile);
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200865 putc('#', dumpfile);
866 }
867 fputs(sym->name, dumpfile);
868 putc(' ', dumpfile);
Andreas Gruenbacher3b40d382008-07-21 04:28:25 +0200869 if (sym->is_extern)
870 fputs("extern ", dumpfile);
Andreas Gruenbacher15fde672006-05-09 20:37:30 +0200871 print_list(dumpfile, sym->defn);
872 putc('\n', dumpfile);
873
874 visited_symbols = sym->visited;
875 sym->visited = NULL;
876 }
877 }
878
Sam Ravnborg78c041532006-03-12 22:59:36 +0100879 if (flag_debug) {
880 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
881 nsyms, HASH_BUCKETS,
882 (double)nsyms / (double)HASH_BUCKETS);
883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
Maxim Zhukov4deaaa42016-04-12 23:54:59 +0300885 if (dumpfile)
886 fclose(dumpfile);
887
Sam Ravnborg78c041532006-03-12 22:59:36 +0100888 return errors != 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889}