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 39static struct symbol *symtab[HASH_BUCKETS]; 40static FILE *debugfile; 41 42int cur_line = 1; 43char *cur_filename; 44 45static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types, 46 flag_preserve, flag_warnings; 47static const char *arch = ""; 48static const char *mod_prefix = ""; 49 50static int errors; 51static int nsyms; 52 53static struct symbol *expansion_trail; 54static struct symbol *visited_symbols; 55 56static const char *const symbol_type_name[] = { 57 "normal", "typedef", "enum", "struct", "union" 58}; 59 60static int equal_list(struct string_list *a, struct string_list *b); 61static void print_list(FILE * f, struct string_list *list); 62static void print_location(void); 63static void print_type_name(enum symbol_type type, const char *name); 64 65/*----------------------------------------------------------------------*/ 66 67static const unsigned int crctab32[] = { 68 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U, 69 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U, 70 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U, 71 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU, 72 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U, 73 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U, 74 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U, 75 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU, 76 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U, 77 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU, 78 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U, 79 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U, 80 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U, 81 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU, 82 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU, 83 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U, 84 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU, 85 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U, 86 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U, 87 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U, 88 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU, 89 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U, 90 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U, 91 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU, 92 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U, 93 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U, 94 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U, 95 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U, 96 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U, 97 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU, 98 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU, 99 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U, 100 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U, 101 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU, 102 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU, 103 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U, 104 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU, 105 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U, 106 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU, 107 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U, 108 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU, 109 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U, 110 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U, 111 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU, 112 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U, 113 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U, 114 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U, 115 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U, 116 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U, 117 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U, 118 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU, 119 0x2d02ef8dU 120}; 121 122static unsigned long partial_crc32_one(unsigned char c, unsigned long crc) 123{ 124 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8); 125} 126 127static unsigned long partial_crc32(const char *s, unsigned long crc) 128{ 129 while (*s) 130 crc = partial_crc32_one(*s++, crc); 131 return crc; 132} 133 134static unsigned long crc32(const char *s) 135{ 136 return partial_crc32(s, 0xffffffff) ^ 0xffffffff; 137} 138 139/*----------------------------------------------------------------------*/ 140 141static enum symbol_type map_to_ns(enum symbol_type t) 142{ 143 if (t == SYM_TYPEDEF) 144 t = SYM_NORMAL; 145 else if (t == SYM_UNION) 146 t = SYM_STRUCT; 147 return t; 148} 149 150struct symbol *find_symbol(const char *name, enum symbol_type ns) 151{ 152 unsigned long h = crc32(name) % HASH_BUCKETS; 153 struct symbol *sym; 154 155 for (sym = symtab[h]; sym; sym = sym->hash_next) 156 if (map_to_ns(sym->type) == map_to_ns(ns) && 157 strcmp(name, sym->name) == 0 && 158 sym->is_declared) 159 break; 160 161 return sym; 162} 163 164static int is_unknown_symbol(struct symbol *sym) 165{ 166 struct string_list *defn; 167 168 return ((sym->type == SYM_STRUCT || 169 sym->type == SYM_UNION || 170 sym->type == SYM_ENUM) && 171 (defn = sym->defn) && defn->tag == SYM_NORMAL && 172 strcmp(defn->string, "}") == 0 && 173 (defn = defn->next) && defn->tag == SYM_NORMAL && 174 strcmp(defn->string, "UNKNOWN") == 0 && 175 (defn = defn->next) && defn->tag == SYM_NORMAL && 176 strcmp(defn->string, "{") == 0); 177} 178 179static struct symbol *__add_symbol(const char *name, enum symbol_type type, 180 struct string_list *defn, int is_extern, 181 int is_reference) 182{ 183 unsigned long h = crc32(name) % HASH_BUCKETS; 184 struct symbol *sym; 185 enum symbol_status status = STATUS_UNCHANGED; 186 187 for (sym = symtab[h]; sym; sym = sym->hash_next) { 188 if (map_to_ns(sym->type) == map_to_ns(type) && 189 strcmp(name, sym->name) == 0) { 190 if (is_reference) 191 /* fall through */ ; 192 else if (sym->type == type && 193 equal_list(sym->defn, defn)) { 194 if (!sym->is_declared && sym->is_override) { 195 print_location(); 196 print_type_name(type, name); 197 fprintf(stderr, " modversion is " 198 "unchanged\n"); 199 } 200 sym->is_declared = 1; 201 return sym; 202 } else if (!sym->is_declared) { 203 if (sym->is_override && flag_preserve) { 204 print_location(); 205 fprintf(stderr, "ignoring "); 206 print_type_name(type, name); 207 fprintf(stderr, " modversion change\n"); 208 sym->is_declared = 1; 209 return sym; 210 } else { 211 status = is_unknown_symbol(sym) ? 212 STATUS_DEFINED : STATUS_MODIFIED; 213 } 214 } else { 215 error_with_pos("redefinition of %s", name); 216 return sym; 217 } 218 break; 219 } 220 } 221 222 if (sym) { 223 struct symbol **psym; 224 225 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) { 226 if (*psym == sym) { 227 *psym = sym->hash_next; 228 break; 229 } 230 } 231 --nsyms; 232 } 233 234 sym = xmalloc(sizeof(*sym)); 235 sym->name = name; 236 sym->type = type; 237 sym->defn = defn; 238 sym->expansion_trail = NULL; 239 sym->visited = NULL; 240 sym->is_extern = is_extern; 241 242 sym->hash_next = symtab[h]; 243 symtab[h] = sym; 244 245 sym->is_declared = !is_reference; 246 sym->status = status; 247 sym->is_override = 0; 248 249 if (flag_debug) { 250 fprintf(debugfile, "Defn for %s %s == <", 251 symbol_type_name[type], name); 252 if (is_extern) 253 fputs("extern ", debugfile); 254 print_list(debugfile, defn); 255 fputs(">\n", debugfile); 256 } 257 258 ++nsyms; 259 return sym; 260} 261 262struct symbol *add_symbol(const char *name, enum symbol_type type, 263 struct string_list *defn, int is_extern) 264{ 265 return __add_symbol(name, type, defn, is_extern, 0); 266} 267 268static struct symbol *add_reference_symbol(const char *name, enum symbol_type type, 269 struct string_list *defn, int is_extern) 270{ 271 return __add_symbol(name, type, defn, is_extern, 1); 272} 273 274/*----------------------------------------------------------------------*/ 275 276void free_node(struct string_list *node) 277{ 278 free(node->string); 279 free(node); 280} 281 282void free_list(struct string_list *s, struct string_list *e) 283{ 284 while (s != e) { 285 struct string_list *next = s->next; 286 free_node(s); 287 s = next; 288 } 289} 290 291struct string_list *copy_node(struct string_list *node) 292{ 293 struct string_list *newnode; 294 295 newnode = xmalloc(sizeof(*newnode)); 296 newnode->string = xstrdup(node->string); 297 newnode->tag = node->tag; 298 299 return newnode; 300} 301 302static int equal_list(struct string_list *a, struct string_list *b) 303{ 304 while (a && b) { 305 if (a->tag != b->tag || strcmp(a->string, b->string)) 306 return 0; 307 a = a->next; 308 b = b->next; 309 } 310 311 return !a && !b; 312} 313 314#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 315 316static struct string_list *read_node(FILE *f) 317{ 318 char buffer[256]; 319 struct string_list node = { 320 .string = buffer, 321 .tag = SYM_NORMAL }; 322 int c; 323 324 while ((c = fgetc(f)) != EOF) { 325 if (c == ' ') { 326 if (node.string == buffer) 327 continue; 328 break; 329 } else if (c == '\n') { 330 if (node.string == buffer) 331 return NULL; 332 ungetc(c, f); 333 break; 334 } 335 if (node.string >= buffer + sizeof(buffer) - 1) { 336 fprintf(stderr, "Token too long\n"); 337 exit(1); 338 } 339 *node.string++ = c; 340 } 341 if (node.string == buffer) 342 return NULL; 343 *node.string = 0; 344 node.string = buffer; 345 346 if (node.string[1] == '#') { 347 int n; 348 349 for (n = 0; n < ARRAY_SIZE(symbol_type_name); n++) { 350 if (node.string[0] == symbol_type_name[n][0]) { 351 node.tag = n; 352 node.string += 2; 353 return copy_node(&node); 354 } 355 } 356 fprintf(stderr, "Unknown type %c\n", node.string[0]); 357 exit(1); 358 } 359 return copy_node(&node); 360} 361 362static void read_reference(FILE *f) 363{ 364 while (!feof(f)) { 365 struct string_list *defn = NULL; 366 struct string_list *sym, *def; 367 int is_extern = 0, is_override = 0; 368 struct symbol *subsym; 369 370 sym = read_node(f); 371 if (sym && sym->tag == SYM_NORMAL && 372 !strcmp(sym->string, "override")) { 373 is_override = 1; 374 free_node(sym); 375 sym = read_node(f); 376 } 377 if (!sym) 378 continue; 379 def = read_node(f); 380 if (def && def->tag == SYM_NORMAL && 381 !strcmp(def->string, "extern")) { 382 is_extern = 1; 383 free_node(def); 384 def = read_node(f); 385 } 386 while (def) { 387 def->next = defn; 388 defn = def; 389 def = read_node(f); 390 } 391 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag, 392 defn, is_extern); 393 subsym->is_override = is_override; 394 free_node(sym); 395 } 396} 397 398static void print_node(FILE * f, struct string_list *list) 399{ 400 if (list->tag != SYM_NORMAL) { 401 putc(symbol_type_name[list->tag][0], f); 402 putc('#', f); 403 } 404 fputs(list->string, f); 405} 406 407static void print_list(FILE * f, struct string_list *list) 408{ 409 struct string_list **e, **b; 410 struct string_list *tmp, **tmp2; 411 int elem = 1; 412 413 if (list == NULL) { 414 fputs("(nil)", f); 415 return; 416 } 417 418 tmp = list; 419 while ((tmp = tmp->next) != NULL) 420 elem++; 421 422 b = alloca(elem * sizeof(*e)); 423 e = b + elem; 424 tmp2 = e - 1; 425 426 (*tmp2--) = list; 427 while ((list = list->next) != NULL) 428 *(tmp2--) = list; 429 430 while (b != e) { 431 print_node(f, *b++); 432 putc(' ', f); 433 } 434} 435 436static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc) 437{ 438 struct string_list *list = sym->defn; 439 struct string_list **e, **b; 440 struct string_list *tmp, **tmp2; 441 int elem = 1; 442 443 if (!list) 444 return crc; 445 446 tmp = list; 447 while ((tmp = tmp->next) != NULL) 448 elem++; 449 450 b = alloca(elem * sizeof(*e)); 451 e = b + elem; 452 tmp2 = e - 1; 453 454 *(tmp2--) = list; 455 while ((list = list->next) != NULL) 456 *(tmp2--) = list; 457 458 while (b != e) { 459 struct string_list *cur; 460 struct symbol *subsym; 461 462 cur = *(b++); 463 switch (cur->tag) { 464 case SYM_NORMAL: 465 if (flag_dump_defs) 466 fprintf(debugfile, "%s ", cur->string); 467 crc = partial_crc32(cur->string, crc); 468 crc = partial_crc32_one(' ', crc); 469 break; 470 471 case SYM_TYPEDEF: 472 subsym = find_symbol(cur->string, cur->tag); 473 if (subsym->expansion_trail) { 474 if (flag_dump_defs) 475 fprintf(debugfile, "%s ", cur->string); 476 crc = partial_crc32(cur->string, crc); 477 crc = partial_crc32_one(' ', crc); 478 } else { 479 subsym->expansion_trail = expansion_trail; 480 expansion_trail = subsym; 481 crc = expand_and_crc_sym(subsym, crc); 482 } 483 break; 484 485 case SYM_STRUCT: 486 case SYM_UNION: 487 case SYM_ENUM: 488 subsym = find_symbol(cur->string, cur->tag); 489 if (!subsym) { 490 struct string_list *n, *t = NULL; 491 492 error_with_pos("expand undefined %s %s", 493 symbol_type_name[cur->tag], 494 cur->string); 495 496 n = xmalloc(sizeof(*n)); 497 n->string = xstrdup(symbol_type_name[cur->tag]); 498 n->tag = SYM_NORMAL; 499 n->next = t; 500 t = n; 501 502 n = xmalloc(sizeof(*n)); 503 n->string = xstrdup(cur->string); 504 n->tag = SYM_NORMAL; 505 n->next = t; 506 t = n; 507 508 n = xmalloc(sizeof(*n)); 509 n->string = xstrdup("{"); 510 n->tag = SYM_NORMAL; 511 n->next = t; 512 t = n; 513 514 n = xmalloc(sizeof(*n)); 515 n->string = xstrdup("UNKNOWN"); 516 n->tag = SYM_NORMAL; 517 n->next = t; 518 t = n; 519 520 n = xmalloc(sizeof(*n)); 521 n->string = xstrdup("}"); 522 n->tag = SYM_NORMAL; 523 n->next = t; 524 t = n; 525 526 subsym = 527 add_symbol(cur->string, cur->tag, n, 0); 528 } 529 if (subsym->expansion_trail) { 530 if (flag_dump_defs) { 531 fprintf(debugfile, "%s %s ", 532 symbol_type_name[cur->tag], 533 cur->string); 534 } 535 536 crc = partial_crc32(symbol_type_name[cur->tag], 537 crc); 538 crc = partial_crc32_one(' ', crc); 539 crc = partial_crc32(cur->string, crc); 540 crc = partial_crc32_one(' ', crc); 541 } else { 542 subsym->expansion_trail = expansion_trail; 543 expansion_trail = subsym; 544 crc = expand_and_crc_sym(subsym, crc); 545 } 546 break; 547 } 548 } 549 550 { 551 static struct symbol **end = &visited_symbols; 552 553 if (!sym->visited) { 554 *end = sym; 555 end = &sym->visited; 556 sym->visited = (struct symbol *)-1L; 557 } 558 } 559 560 return crc; 561} 562 563void export_symbol(const char *name) 564{ 565 struct symbol *sym; 566 567 sym = find_symbol(name, SYM_NORMAL); 568 if (!sym) 569 error_with_pos("export undefined symbol %s", name); 570 else { 571 unsigned long crc; 572 int has_changed = 0; 573 574 if (flag_dump_defs) 575 fprintf(debugfile, "Export %s == <", name); 576 577 expansion_trail = (struct symbol *)-1L; 578 579 sym->expansion_trail = expansion_trail; 580 expansion_trail = sym; 581 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff; 582 583 sym = expansion_trail; 584 while (sym != (struct symbol *)-1L) { 585 struct symbol *n = sym->expansion_trail; 586 587 if (sym->status != STATUS_UNCHANGED) { 588 if (!has_changed) { 589 print_location(); 590 fprintf(stderr, "%s: %s: modversion " 591 "changed because of changes " 592 "in ", flag_preserve ? "error" : 593 "warning", name); 594 } else 595 fprintf(stderr, ", "); 596 print_type_name(sym->type, sym->name); 597 if (sym->status == STATUS_DEFINED) 598 fprintf(stderr, " (became defined)"); 599 has_changed = 1; 600 if (flag_preserve) 601 errors++; 602 } 603 sym->expansion_trail = 0; 604 sym = n; 605 } 606 if (has_changed) 607 fprintf(stderr, "\n"); 608 609 if (flag_dump_defs) 610 fputs(">\n", debugfile); 611 612 /* Used as a linker script. */ 613 printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc); 614 } 615} 616 617/*----------------------------------------------------------------------*/ 618 619static void print_location(void) 620{ 621 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line); 622} 623 624static void print_type_name(enum symbol_type type, const char *name) 625{ 626 if (type != SYM_NORMAL) 627 fprintf(stderr, "%s %s", symbol_type_name[type], name); 628 else 629 fprintf(stderr, "%s", name); 630} 631 632void error_with_pos(const char *fmt, ...) 633{ 634 va_list args; 635 636 if (flag_warnings) { 637 print_location(); 638 639 va_start(args, fmt); 640 vfprintf(stderr, fmt, args); 641 va_end(args); 642 putc('\n', stderr); 643 644 errors++; 645 } 646} 647 648static void genksyms_usage(void) 649{ 650 fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n" 651#ifdef __GNU_LIBRARY__ 652 " -a, --arch Select architecture\n" 653 " -d, --debug Increment the debug level (repeatable)\n" 654 " -D, --dump Dump expanded symbol defs (for debugging only)\n" 655 " -r, --reference file Read reference symbols from a file\n" 656 " -T, --dump-types file Dump expanded types into file\n" 657 " -p, --preserve Preserve reference modversions or fail\n" 658 " -w, --warnings Enable warnings\n" 659 " -q, --quiet Disable warnings (default)\n" 660 " -h, --help Print this message\n" 661 " -V, --version Print the release version\n" 662#else /* __GNU_LIBRARY__ */ 663 " -a Select architecture\n" 664 " -d Increment the debug level (repeatable)\n" 665 " -D Dump expanded symbol defs (for debugging only)\n" 666 " -r file Read reference symbols from a file\n" 667 " -T file Dump expanded types into file\n" 668 " -p Preserve reference modversions or fail\n" 669 " -w Enable warnings\n" 670 " -q Disable warnings (default)\n" 671 " -h Print this message\n" 672 " -V Print the release version\n" 673#endif /* __GNU_LIBRARY__ */ 674 , stderr); 675} 676 677int main(int argc, char **argv) 678{ 679 FILE *dumpfile = NULL, *ref_file = NULL; 680 int o; 681 682#ifdef __GNU_LIBRARY__ 683 struct option long_opts[] = { 684 {"arch", 1, 0, 'a'}, 685 {"debug", 0, 0, 'd'}, 686 {"warnings", 0, 0, 'w'}, 687 {"quiet", 0, 0, 'q'}, 688 {"dump", 0, 0, 'D'}, 689 {"reference", 1, 0, 'r'}, 690 {"dump-types", 1, 0, 'T'}, 691 {"preserve", 0, 0, 'p'}, 692 {"version", 0, 0, 'V'}, 693 {"help", 0, 0, 'h'}, 694 {0, 0, 0, 0} 695 }; 696 697 while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph", 698 &long_opts[0], NULL)) != EOF) 699#else /* __GNU_LIBRARY__ */ 700 while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF) 701#endif /* __GNU_LIBRARY__ */ 702 switch (o) { 703 case 'a': 704 arch = optarg; 705 break; 706 case 'd': 707 flag_debug++; 708 break; 709 case 'w': 710 flag_warnings = 1; 711 break; 712 case 'q': 713 flag_warnings = 0; 714 break; 715 case 'V': 716 fputs("genksyms version 2.5.60\n", stderr); 717 break; 718 case 'D': 719 flag_dump_defs = 1; 720 break; 721 case 'r': 722 flag_reference = 1; 723 ref_file = fopen(optarg, "r"); 724 if (!ref_file) { 725 perror(optarg); 726 return 1; 727 } 728 break; 729 case 'T': 730 flag_dump_types = 1; 731 dumpfile = fopen(optarg, "w"); 732 if (!dumpfile) { 733 perror(optarg); 734 return 1; 735 } 736 break; 737 case 'p': 738 flag_preserve = 1; 739 break; 740 case 'h': 741 genksyms_usage(); 742 return 0; 743 default: 744 genksyms_usage(); 745 return 1; 746 } 747 if ((strcmp(arch, "h8300") == 0) || (strcmp(arch, "blackfin") == 0)) 748 mod_prefix = "_"; 749 { 750 extern int yydebug; 751 extern int yy_flex_debug; 752 753 yydebug = (flag_debug > 1); 754 yy_flex_debug = (flag_debug > 2); 755 756 debugfile = stderr; 757 /* setlinebuf(debugfile); */ 758 } 759 760 if (flag_reference) { 761 read_reference(ref_file); 762 fclose(ref_file); 763 } 764 765 yyparse(); 766 767 if (flag_dump_types && visited_symbols) { 768 while (visited_symbols != (struct symbol *)-1L) { 769 struct symbol *sym = visited_symbols; 770 771 if (sym->is_override) 772 fputs("override ", dumpfile); 773 if (sym->type != SYM_NORMAL) { 774 putc(symbol_type_name[sym->type][0], dumpfile); 775 putc('#', dumpfile); 776 } 777 fputs(sym->name, dumpfile); 778 putc(' ', dumpfile); 779 if (sym->is_extern) 780 fputs("extern ", dumpfile); 781 print_list(dumpfile, sym->defn); 782 putc('\n', dumpfile); 783 784 visited_symbols = sym->visited; 785 sym->visited = NULL; 786 } 787 } 788 789 if (flag_debug) { 790 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n", 791 nsyms, HASH_BUCKETS, 792 (double)nsyms / (double)HASH_BUCKETS); 793 } 794 795 return errors != 0; 796} 797