linux/scripts/genksyms/genksyms.c
<<
>>
Prefs
   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                        /* FIXME: Bad reference files can segfault here. */
 474                        if (subsym->expansion_trail) {
 475                                if (flag_dump_defs)
 476                                        fprintf(debugfile, "%s ", cur->string);
 477                                crc = partial_crc32(cur->string, crc);
 478                                crc = partial_crc32_one(' ', crc);
 479                        } else {
 480                                subsym->expansion_trail = expansion_trail;
 481                                expansion_trail = subsym;
 482                                crc = expand_and_crc_sym(subsym, crc);
 483                        }
 484                        break;
 485
 486                case SYM_STRUCT:
 487                case SYM_UNION:
 488                case SYM_ENUM:
 489                        subsym = find_symbol(cur->string, cur->tag);
 490                        if (!subsym) {
 491                                struct string_list *n, *t = NULL;
 492
 493                                error_with_pos("expand undefined %s %s",
 494                                               symbol_type_name[cur->tag],
 495                                               cur->string);
 496
 497                                n = xmalloc(sizeof(*n));
 498                                n->string = xstrdup(symbol_type_name[cur->tag]);
 499                                n->tag = SYM_NORMAL;
 500                                n->next = t;
 501                                t = n;
 502
 503                                n = xmalloc(sizeof(*n));
 504                                n->string = xstrdup(cur->string);
 505                                n->tag = SYM_NORMAL;
 506                                n->next = t;
 507                                t = n;
 508
 509                                n = xmalloc(sizeof(*n));
 510                                n->string = xstrdup("{");
 511                                n->tag = SYM_NORMAL;
 512                                n->next = t;
 513                                t = n;
 514
 515                                n = xmalloc(sizeof(*n));
 516                                n->string = xstrdup("UNKNOWN");
 517                                n->tag = SYM_NORMAL;
 518                                n->next = t;
 519                                t = n;
 520
 521                                n = xmalloc(sizeof(*n));
 522                                n->string = xstrdup("}");
 523                                n->tag = SYM_NORMAL;
 524                                n->next = t;
 525                                t = n;
 526
 527                                subsym =
 528                                    add_symbol(cur->string, cur->tag, n, 0);
 529                        }
 530                        if (subsym->expansion_trail) {
 531                                if (flag_dump_defs) {
 532                                        fprintf(debugfile, "%s %s ",
 533                                                symbol_type_name[cur->tag],
 534                                                cur->string);
 535                                }
 536
 537                                crc = partial_crc32(symbol_type_name[cur->tag],
 538                                                    crc);
 539                                crc = partial_crc32_one(' ', crc);
 540                                crc = partial_crc32(cur->string, crc);
 541                                crc = partial_crc32_one(' ', crc);
 542                        } else {
 543                                subsym->expansion_trail = expansion_trail;
 544                                expansion_trail = subsym;
 545                                crc = expand_and_crc_sym(subsym, crc);
 546                        }
 547                        break;
 548                }
 549        }
 550
 551        {
 552                static struct symbol **end = &visited_symbols;
 553
 554                if (!sym->visited) {
 555                        *end = sym;
 556                        end = &sym->visited;
 557                        sym->visited = (struct symbol *)-1L;
 558                }
 559        }
 560
 561        return crc;
 562}
 563
 564void export_symbol(const char *name)
 565{
 566        struct symbol *sym;
 567
 568        sym = find_symbol(name, SYM_NORMAL);
 569        if (!sym)
 570                error_with_pos("export undefined symbol %s", name);
 571        else {
 572                unsigned long crc;
 573                int has_changed = 0;
 574
 575                if (flag_dump_defs)
 576                        fprintf(debugfile, "Export %s == <", name);
 577
 578                expansion_trail = (struct symbol *)-1L;
 579
 580                sym->expansion_trail = expansion_trail;
 581                expansion_trail = sym;
 582                crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
 583
 584                sym = expansion_trail;
 585                while (sym != (struct symbol *)-1L) {
 586                        struct symbol *n = sym->expansion_trail;
 587
 588                        if (sym->status != STATUS_UNCHANGED) {
 589                                if (!has_changed) {
 590                                        print_location();
 591                                        fprintf(stderr, "%s: %s: modversion "
 592                                                "changed because of changes "
 593                                                "in ", flag_preserve ? "error" :
 594                                                       "warning", name);
 595                                } else
 596                                        fprintf(stderr, ", ");
 597                                print_type_name(sym->type, sym->name);
 598                                if (sym->status == STATUS_DEFINED)
 599                                        fprintf(stderr, " (became defined)");
 600                                has_changed = 1;
 601                                if (flag_preserve)
 602                                        errors++;
 603                        }
 604                        sym->expansion_trail = 0;
 605                        sym = n;
 606                }
 607                if (has_changed)
 608                        fprintf(stderr, "\n");
 609
 610                if (flag_dump_defs)
 611                        fputs(">\n", debugfile);
 612
 613                /* Used as a linker script. */
 614                printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
 615        }
 616}
 617
 618/*----------------------------------------------------------------------*/
 619
 620static void print_location(void)
 621{
 622        fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
 623}
 624
 625static void print_type_name(enum symbol_type type, const char *name)
 626{
 627        if (type != SYM_NORMAL)
 628                fprintf(stderr, "%s %s", symbol_type_name[type], name);
 629        else
 630                fprintf(stderr, "%s", name);
 631}
 632
 633void error_with_pos(const char *fmt, ...)
 634{
 635        va_list args;
 636
 637        if (flag_warnings) {
 638                print_location();
 639
 640                va_start(args, fmt);
 641                vfprintf(stderr, fmt, args);
 642                va_end(args);
 643                putc('\n', stderr);
 644
 645                errors++;
 646        }
 647}
 648
 649static void genksyms_usage(void)
 650{
 651        fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
 652#ifdef __GNU_LIBRARY__
 653              "  -a, --arch            Select architecture\n"
 654              "  -d, --debug           Increment the debug level (repeatable)\n"
 655              "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
 656              "  -r, --reference file  Read reference symbols from a file\n"
 657              "  -T, --dump-types file Dump expanded types into file\n"
 658              "  -p, --preserve        Preserve reference modversions or fail\n"
 659              "  -w, --warnings        Enable warnings\n"
 660              "  -q, --quiet           Disable warnings (default)\n"
 661              "  -h, --help            Print this message\n"
 662              "  -V, --version         Print the release version\n"
 663#else                           /* __GNU_LIBRARY__ */
 664              "  -a                    Select architecture\n"
 665              "  -d                    Increment the debug level (repeatable)\n"
 666              "  -D                    Dump expanded symbol defs (for debugging only)\n"
 667              "  -r file               Read reference symbols from a file\n"
 668              "  -T file               Dump expanded types into file\n"
 669              "  -p                    Preserve reference modversions or fail\n"
 670              "  -w                    Enable warnings\n"
 671              "  -q                    Disable warnings (default)\n"
 672              "  -h                    Print this message\n"
 673              "  -V                    Print the release version\n"
 674#endif                          /* __GNU_LIBRARY__ */
 675              , stderr);
 676}
 677
 678int main(int argc, char **argv)
 679{
 680        FILE *dumpfile = NULL, *ref_file = NULL;
 681        int o;
 682
 683#ifdef __GNU_LIBRARY__
 684        struct option long_opts[] = {
 685                {"arch", 1, 0, 'a'},
 686                {"debug", 0, 0, 'd'},
 687                {"warnings", 0, 0, 'w'},
 688                {"quiet", 0, 0, 'q'},
 689                {"dump", 0, 0, 'D'},
 690                {"reference", 1, 0, 'r'},
 691                {"dump-types", 1, 0, 'T'},
 692                {"preserve", 0, 0, 'p'},
 693                {"version", 0, 0, 'V'},
 694                {"help", 0, 0, 'h'},
 695                {0, 0, 0, 0}
 696        };
 697
 698        while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph",
 699                                &long_opts[0], NULL)) != EOF)
 700#else                           /* __GNU_LIBRARY__ */
 701        while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF)
 702#endif                          /* __GNU_LIBRARY__ */
 703                switch (o) {
 704                case 'a':
 705                        arch = optarg;
 706                        break;
 707                case 'd':
 708                        flag_debug++;
 709                        break;
 710                case 'w':
 711                        flag_warnings = 1;
 712                        break;
 713                case 'q':
 714                        flag_warnings = 0;
 715                        break;
 716                case 'V':
 717                        fputs("genksyms version 2.5.60\n", stderr);
 718                        break;
 719                case 'D':
 720                        flag_dump_defs = 1;
 721                        break;
 722                case 'r':
 723                        flag_reference = 1;
 724                        ref_file = fopen(optarg, "r");
 725                        if (!ref_file) {
 726                                perror(optarg);
 727                                return 1;
 728                        }
 729                        break;
 730                case 'T':
 731                        flag_dump_types = 1;
 732                        dumpfile = fopen(optarg, "w");
 733                        if (!dumpfile) {
 734                                perror(optarg);
 735                                return 1;
 736                        }
 737                        break;
 738                case 'p':
 739                        flag_preserve = 1;
 740                        break;
 741                case 'h':
 742                        genksyms_usage();
 743                        return 0;
 744                default:
 745                        genksyms_usage();
 746                        return 1;
 747                }
 748        if ((strcmp(arch, "h8300") == 0) || (strcmp(arch, "blackfin") == 0))
 749                mod_prefix = "_";
 750        {
 751                extern int yydebug;
 752                extern int yy_flex_debug;
 753
 754                yydebug = (flag_debug > 1);
 755                yy_flex_debug = (flag_debug > 2);
 756
 757                debugfile = stderr;
 758                /* setlinebuf(debugfile); */
 759        }
 760
 761        if (flag_reference) {
 762                read_reference(ref_file);
 763                fclose(ref_file);
 764        }
 765
 766        yyparse();
 767
 768        if (flag_dump_types && visited_symbols) {
 769                while (visited_symbols != (struct symbol *)-1L) {
 770                        struct symbol *sym = visited_symbols;
 771
 772                        if (sym->is_override)
 773                                fputs("override ", dumpfile);
 774                        if (sym->type != SYM_NORMAL) {
 775                                putc(symbol_type_name[sym->type][0], dumpfile);
 776                                putc('#', dumpfile);
 777                        }
 778                        fputs(sym->name, dumpfile);
 779                        putc(' ', dumpfile);
 780                        if (sym->is_extern)
 781                                fputs("extern ", dumpfile);
 782                        print_list(dumpfile, sym->defn);
 783                        putc('\n', dumpfile);
 784
 785                        visited_symbols = sym->visited;
 786                        sym->visited = NULL;
 787                }
 788        }
 789
 790        if (flag_debug) {
 791                fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
 792                        nsyms, HASH_BUCKETS,
 793                        (double)nsyms / (double)HASH_BUCKETS);
 794        }
 795
 796        return errors != 0;
 797}
 798