1 /* 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> 32 #endif /* __GNU_LIBRARY__ */ 33 34 #include "genksyms.h" 35 /*----------------------------------------------------------------------*/ 36 37 #define HASH_BUCKETS 4096 38 39 static struct symbol *symtab[HASH_BUCKETS]; 40 static FILE *debugfile; 41 42 int cur_line = 1; 43 char *cur_filename; 44 45 static int flag_debug, flag_dump_defs, flag_warnings; 46 static const char *arch = ""; 47 static const char *mod_prefix = ""; 48 49 static int errors; 50 static int nsyms; 51 52 static struct symbol *expansion_trail; 53 54 static const char *const symbol_type_name[] = { 55 "normal", "typedef", "enum", "struct", "union" 56 }; 57 58 static int equal_list(struct string_list *a, struct string_list *b); 59 static void print_list(FILE * f, struct string_list *list); 60 61 /*----------------------------------------------------------------------*/ 62 63 static const unsigned int crctab32[] = { 64 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U, 65 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U, 66 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, 67 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU, 68 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U, 69 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U, 70 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, 71 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, 72 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, 73 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU, 74 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, 75 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U, 76 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U, 77 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU, 78 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, 79 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U, 80 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU, 81 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U, 82 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, 83 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U, 84 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU, 85 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U, 86 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U, 87 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU, 88 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, 89 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U, 90 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U, 91 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U, 92 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U, 93 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU, 94 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU, 95 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U, 96 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U, 97 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU, 98 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU, 99 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U, 100 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU, 101 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U, 102 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, 103 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U, 104 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU, 105 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U, 106 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, 107 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU, 108 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U, 109 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U, 110 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U, 111 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U, 112 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U, 113 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U, 114 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, 115 0x2d02ef8dU 116 }; 117 118 static unsigned long partial_crc32_one(unsigned char c, unsigned long crc) 119 { 120 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8); 121 } 122 123 static unsigned long partial_crc32(const char *s, unsigned long crc) 124 { 125 while (*s) 126 crc = partial_crc32_one(*s++, crc); 127 return crc; 128 } 129 130 static unsigned long crc32(const char *s) 131 { 132 return partial_crc32(s, 0xffffffff) ^ 0xffffffff; 133 } 134 135 /*----------------------------------------------------------------------*/ 136 137 static enum symbol_type map_to_ns(enum symbol_type t) 138 { 139 if (t == SYM_TYPEDEF) 140 t = SYM_NORMAL; 141 else if (t == SYM_UNION) 142 t = SYM_STRUCT; 143 return t; 144 } 145 146 struct symbol *find_symbol(const char *name, enum symbol_type ns) 147 { 148 unsigned long h = crc32(name) % HASH_BUCKETS; 149 struct symbol *sym; 150 151 for (sym = symtab[h]; sym; sym = sym->hash_next) 152 if (map_to_ns(sym->type) == map_to_ns(ns) && 153 strcmp(name, sym->name) == 0) 154 break; 155 156 return sym; 157 } 158 159 struct symbol *add_symbol(const char *name, enum symbol_type type, 160 struct string_list *defn, int is_extern) 161 { 162 unsigned long h = crc32(name) % HASH_BUCKETS; 163 struct symbol *sym; 164 165 for (sym = symtab[h]; sym; sym = sym->hash_next) { 166 if (map_to_ns(sym->type) == map_to_ns(type) 167 && strcmp(name, sym->name) == 0) { 168 if (!equal_list(sym->defn, defn)) 169 error_with_pos("redefinition of %s", name); 170 return sym; 171 } 172 } 173 174 sym = xmalloc(sizeof(*sym)); 175 sym->name = name; 176 sym->type = type; 177 sym->defn = defn; 178 sym->expansion_trail = NULL; 179 sym->is_extern = is_extern; 180 181 sym->hash_next = symtab[h]; 182 symtab[h] = sym; 183 184 if (flag_debug) { 185 fprintf(debugfile, "Defn for %s %s == <", 186 symbol_type_name[type], name); 187 if (is_extern) 188 fputs("extern ", debugfile); 189 print_list(debugfile, defn); 190 fputs(">\n", debugfile); 191 } 192 193 ++nsyms; 194 return sym; 195 } 196 197 /*----------------------------------------------------------------------*/ 198 199 void free_node(struct string_list *node) 200 { 201 free(node->string); 202 free(node); 203 } 204 205 void free_list(struct string_list *s, struct string_list *e) 206 { 207 while (s != e) { 208 struct string_list *next = s->next; 209 free_node(s); 210 s = next; 211 } 212 } 213 214 struct string_list *copy_node(struct string_list *node) 215 { 216 struct string_list *newnode; 217 218 newnode = xmalloc(sizeof(*newnode)); 219 newnode->string = xstrdup(node->string); 220 newnode->tag = node->tag; 221 222 return newnode; 223 } 224 225 static int equal_list(struct string_list *a, struct string_list *b) 226 { 227 while (a && b) { 228 if (a->tag != b->tag || strcmp(a->string, b->string)) 229 return 0; 230 a = a->next; 231 b = b->next; 232 } 233 234 return !a && !b; 235 } 236 237 static void print_node(FILE * f, struct string_list *list) 238 { 239 switch (list->tag) { 240 case SYM_STRUCT: 241 putc('s', f); 242 goto printit; 243 case SYM_UNION: 244 putc('u', f); 245 goto printit; 246 case SYM_ENUM: 247 putc('e', f); 248 goto printit; 249 case SYM_TYPEDEF: 250 putc('t', f); 251 goto printit; 252 253 printit: 254 putc('#', f); 255 case SYM_NORMAL: 256 fputs(list->string, f); 257 break; 258 } 259 } 260 261 static void print_list(FILE * f, struct string_list *list) 262 { 263 struct string_list **e, **b; 264 struct string_list *tmp, **tmp2; 265 int elem = 1; 266 267 if (list == NULL) { 268 fputs("(nil)", f); 269 return; 270 } 271 272 tmp = list; 273 while ((tmp = tmp->next) != NULL) 274 elem++; 275 276 b = alloca(elem * sizeof(*e)); 277 e = b + elem; 278 tmp2 = e - 1; 279 280 (*tmp2--) = list; 281 while ((list = list->next) != NULL) 282 *(tmp2--) = list; 283 284 while (b != e) { 285 print_node(f, *b++); 286 putc(' ', f); 287 } 288 } 289 290 static unsigned long expand_and_crc_list(struct string_list *list, 291 unsigned long crc) 292 { 293 struct string_list **e, **b; 294 struct string_list *tmp, **tmp2; 295 int elem = 1; 296 297 if (!list) 298 return crc; 299 300 tmp = list; 301 while ((tmp = tmp->next) != NULL) 302 elem++; 303 304 b = alloca(elem * sizeof(*e)); 305 e = b + elem; 306 tmp2 = e - 1; 307 308 *(tmp2--) = list; 309 while ((list = list->next) != NULL) 310 *(tmp2--) = list; 311 312 while (b != e) { 313 struct string_list *cur; 314 struct symbol *subsym; 315 316 cur = *(b++); 317 switch (cur->tag) { 318 case SYM_NORMAL: 319 if (flag_dump_defs) 320 fprintf(debugfile, "%s ", cur->string); 321 crc = partial_crc32(cur->string, crc); 322 crc = partial_crc32_one(' ', crc); 323 break; 324 325 case SYM_TYPEDEF: 326 subsym = find_symbol(cur->string, cur->tag); 327 if (subsym->expansion_trail) { 328 if (flag_dump_defs) 329 fprintf(debugfile, "%s ", cur->string); 330 crc = partial_crc32(cur->string, crc); 331 crc = partial_crc32_one(' ', crc); 332 } else { 333 subsym->expansion_trail = expansion_trail; 334 expansion_trail = subsym; 335 crc = expand_and_crc_list(subsym->defn, crc); 336 } 337 break; 338 339 case SYM_STRUCT: 340 case SYM_UNION: 341 case SYM_ENUM: 342 subsym = find_symbol(cur->string, cur->tag); 343 if (!subsym) { 344 struct string_list *n, *t = NULL; 345 346 error_with_pos("expand undefined %s %s", 347 symbol_type_name[cur->tag], 348 cur->string); 349 350 n = xmalloc(sizeof(*n)); 351 n->string = xstrdup(symbol_type_name[cur->tag]); 352 n->tag = SYM_NORMAL; 353 n->next = t; 354 t = n; 355 356 n = xmalloc(sizeof(*n)); 357 n->string = xstrdup(cur->string); 358 n->tag = SYM_NORMAL; 359 n->next = t; 360 t = n; 361 362 n = xmalloc(sizeof(*n)); 363 n->string = xstrdup("{ UNKNOWN }"); 364 n->tag = SYM_NORMAL; 365 n->next = t; 366 367 subsym = 368 add_symbol(cur->string, cur->tag, n, 0); 369 } 370 if (subsym->expansion_trail) { 371 if (flag_dump_defs) { 372 fprintf(debugfile, "%s %s ", 373 symbol_type_name[cur->tag], 374 cur->string); 375 } 376 377 crc = partial_crc32(symbol_type_name[cur->tag], 378 crc); 379 crc = partial_crc32_one(' ', crc); 380 crc = partial_crc32(cur->string, crc); 381 crc = partial_crc32_one(' ', crc); 382 } else { 383 subsym->expansion_trail = expansion_trail; 384 expansion_trail = subsym; 385 crc = expand_and_crc_list(subsym->defn, crc); 386 } 387 break; 388 } 389 } 390 391 return crc; 392 } 393 394 void export_symbol(const char *name) 395 { 396 struct symbol *sym; 397 398 sym = find_symbol(name, SYM_NORMAL); 399 if (!sym) 400 error_with_pos("export undefined symbol %s", name); 401 else { 402 unsigned long crc; 403 404 if (flag_dump_defs) 405 fprintf(debugfile, "Export %s == <", name); 406 407 expansion_trail = (struct symbol *)-1L; 408 409 crc = expand_and_crc_list(sym->defn, 0xffffffff) ^ 0xffffffff; 410 411 sym = expansion_trail; 412 while (sym != (struct symbol *)-1L) { 413 struct symbol *n = sym->expansion_trail; 414 sym->expansion_trail = 0; 415 sym = n; 416 } 417 418 if (flag_dump_defs) 419 fputs(">\n", debugfile); 420 421 /* Used as a linker script. */ 422 printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc); 423 } 424 } 425 426 /*----------------------------------------------------------------------*/ 427 void error_with_pos(const char *fmt, ...) 428 { 429 va_list args; 430 431 if (flag_warnings) { 432 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", 433 cur_line); 434 435 va_start(args, fmt); 436 vfprintf(stderr, fmt, args); 437 va_end(args); 438 putc('\n', stderr); 439 440 errors++; 441 } 442 } 443 444 static void genksyms_usage(void) 445 { 446 fputs("Usage:\n" "genksyms [-dDwqhV] > /path/to/.tmp_obj.ver\n" "\n" 447 #ifdef __GNU_LIBRARY__ 448 " -d, --debug Increment the debug level (repeatable)\n" 449 " -D, --dump Dump expanded symbol defs (for debugging only)\n" 450 " -w, --warnings Enable warnings\n" 451 " -q, --quiet Disable warnings (default)\n" 452 " -h, --help Print this message\n" 453 " -V, --version Print the release version\n" 454 #else /* __GNU_LIBRARY__ */ 455 " -d Increment the debug level (repeatable)\n" 456 " -D Dump expanded symbol defs (for debugging only)\n" 457 " -w Enable warnings\n" 458 " -q Disable warnings (default)\n" 459 " -h Print this message\n" 460 " -V Print the release version\n" 461 #endif /* __GNU_LIBRARY__ */ 462 , stderr); 463 } 464 465 int main(int argc, char **argv) 466 { 467 int o; 468 469 #ifdef __GNU_LIBRARY__ 470 struct option long_opts[] = { 471 {"arch", 1, 0, 'a'}, 472 {"debug", 0, 0, 'd'}, 473 {"warnings", 0, 0, 'w'}, 474 {"quiet", 0, 0, 'q'}, 475 {"dump", 0, 0, 'D'}, 476 {"version", 0, 0, 'V'}, 477 {"help", 0, 0, 'h'}, 478 {0, 0, 0, 0} 479 }; 480 481 while ((o = getopt_long(argc, argv, "a:dwqVDk:p:", 482 &long_opts[0], NULL)) != EOF) 483 #else /* __GNU_LIBRARY__ */ 484 while ((o = getopt(argc, argv, "a:dwqVDk:p:")) != EOF) 485 #endif /* __GNU_LIBRARY__ */ 486 switch (o) { 487 case 'a': 488 arch = optarg; 489 break; 490 case 'd': 491 flag_debug++; 492 break; 493 case 'w': 494 flag_warnings = 1; 495 break; 496 case 'q': 497 flag_warnings = 0; 498 break; 499 case 'V': 500 fputs("genksyms version 2.5.60\n", stderr); 501 break; 502 case 'D': 503 flag_dump_defs = 1; 504 break; 505 case 'h': 506 genksyms_usage(); 507 return 0; 508 default: 509 genksyms_usage(); 510 return 1; 511 } 512 if ((strcmp(arch, "v850") == 0) || (strcmp(arch, "h8300") == 0)) 513 mod_prefix = "_"; 514 { 515 extern int yydebug; 516 extern int yy_flex_debug; 517 518 yydebug = (flag_debug > 1); 519 yy_flex_debug = (flag_debug > 2); 520 521 debugfile = stderr; 522 /* setlinebuf(debugfile); */ 523 } 524 525 yyparse(); 526 527 if (flag_debug) { 528 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n", 529 nsyms, HASH_BUCKETS, 530 (double)nsyms / (double)HASH_BUCKETS); 531 } 532 533 return errors != 0; 534 } 535