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