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