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, *source_file;
  33int in_source_file;
  34
  35static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
  36           flag_preserve, flag_warnings, flag_rel_crcs;
  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                /* Used as a linker script. */
 684                printf(!flag_rel_crcs ? "__crc_%s = 0x%08lx;\n" :
 685                       "SECTIONS { .rodata : ALIGN(4) { "
 686                       "__crc_%s = .; LONG(0x%08lx); } }\n",
 687                       name, crc);
 688        }
 689}
 690
 691/*----------------------------------------------------------------------*/
 692
 693static void print_location(void)
 694{
 695        fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
 696}
 697
 698static void print_type_name(enum symbol_type type, const char *name)
 699{
 700        if (symbol_types[type].name)
 701                fprintf(stderr, "%s %s", symbol_types[type].name, name);
 702        else
 703                fprintf(stderr, "%s", name);
 704}
 705
 706void error_with_pos(const char *fmt, ...)
 707{
 708        va_list args;
 709
 710        if (flag_warnings) {
 711                print_location();
 712
 713                va_start(args, fmt);
 714                vfprintf(stderr, fmt, args);
 715                va_end(args);
 716                putc('\n', stderr);
 717
 718                errors++;
 719        }
 720}
 721
 722static void genksyms_usage(void)
 723{
 724        fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
 725#ifdef __GNU_LIBRARY__
 726              "  -s, --symbol-prefix   Select symbol prefix\n"
 727              "  -d, --debug           Increment the debug level (repeatable)\n"
 728              "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
 729              "  -r, --reference file  Read reference symbols from a file\n"
 730              "  -T, --dump-types file Dump expanded types into file\n"
 731              "  -p, --preserve        Preserve reference modversions or fail\n"
 732              "  -w, --warnings        Enable warnings\n"
 733              "  -q, --quiet           Disable warnings (default)\n"
 734              "  -h, --help            Print this message\n"
 735              "  -V, --version         Print the release version\n"
 736              "  -R, --relative-crc    Emit section relative symbol CRCs\n"
 737#else                           /* __GNU_LIBRARY__ */
 738              "  -s                    Select symbol prefix\n"
 739              "  -d                    Increment the debug level (repeatable)\n"
 740              "  -D                    Dump expanded symbol defs (for debugging only)\n"
 741              "  -r file               Read reference symbols from a file\n"
 742              "  -T file               Dump expanded types into file\n"
 743              "  -p                    Preserve reference modversions or fail\n"
 744              "  -w                    Enable warnings\n"
 745              "  -q                    Disable warnings (default)\n"
 746              "  -h                    Print this message\n"
 747              "  -V                    Print the release version\n"
 748              "  -R                    Emit section relative symbol CRCs\n"
 749#endif                          /* __GNU_LIBRARY__ */
 750              , stderr);
 751}
 752
 753int main(int argc, char **argv)
 754{
 755        FILE *dumpfile = NULL, *ref_file = NULL;
 756        int o;
 757
 758#ifdef __GNU_LIBRARY__
 759        struct option long_opts[] = {
 760                {"debug", 0, 0, 'd'},
 761                {"warnings", 0, 0, 'w'},
 762                {"quiet", 0, 0, 'q'},
 763                {"dump", 0, 0, 'D'},
 764                {"reference", 1, 0, 'r'},
 765                {"dump-types", 1, 0, 'T'},
 766                {"preserve", 0, 0, 'p'},
 767                {"version", 0, 0, 'V'},
 768                {"help", 0, 0, 'h'},
 769                {"relative-crc", 0, 0, 'R'},
 770                {0, 0, 0, 0}
 771        };
 772
 773        while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
 774                                &long_opts[0], NULL)) != EOF)
 775#else                           /* __GNU_LIBRARY__ */
 776        while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
 777#endif                          /* __GNU_LIBRARY__ */
 778                switch (o) {
 779                case 'd':
 780                        flag_debug++;
 781                        break;
 782                case 'w':
 783                        flag_warnings = 1;
 784                        break;
 785                case 'q':
 786                        flag_warnings = 0;
 787                        break;
 788                case 'V':
 789                        fputs("genksyms version 2.5.60\n", stderr);
 790                        break;
 791                case 'D':
 792                        flag_dump_defs = 1;
 793                        break;
 794                case 'r':
 795                        flag_reference = 1;
 796                        ref_file = fopen(optarg, "r");
 797                        if (!ref_file) {
 798                                perror(optarg);
 799                                return 1;
 800                        }
 801                        break;
 802                case 'T':
 803                        flag_dump_types = 1;
 804                        dumpfile = fopen(optarg, "w");
 805                        if (!dumpfile) {
 806                                perror(optarg);
 807                                return 1;
 808                        }
 809                        break;
 810                case 'p':
 811                        flag_preserve = 1;
 812                        break;
 813                case 'h':
 814                        genksyms_usage();
 815                        return 0;
 816                case 'R':
 817                        flag_rel_crcs = 1;
 818                        break;
 819                default:
 820                        genksyms_usage();
 821                        return 1;
 822                }
 823        {
 824                extern int yydebug;
 825                extern int yy_flex_debug;
 826
 827                yydebug = (flag_debug > 1);
 828                yy_flex_debug = (flag_debug > 2);
 829
 830                debugfile = stderr;
 831                /* setlinebuf(debugfile); */
 832        }
 833
 834        if (flag_reference) {
 835                read_reference(ref_file);
 836                fclose(ref_file);
 837        }
 838
 839        yyparse();
 840
 841        if (flag_dump_types && visited_symbols) {
 842                while (visited_symbols != (struct symbol *)-1L) {
 843                        struct symbol *sym = visited_symbols;
 844
 845                        if (sym->is_override)
 846                                fputs("override ", dumpfile);
 847                        if (symbol_types[sym->type].n) {
 848                                putc(symbol_types[sym->type].n, dumpfile);
 849                                putc('#', dumpfile);
 850                        }
 851                        fputs(sym->name, dumpfile);
 852                        putc(' ', dumpfile);
 853                        if (sym->is_extern)
 854                                fputs("extern ", dumpfile);
 855                        print_list(dumpfile, sym->defn);
 856                        putc('\n', dumpfile);
 857
 858                        visited_symbols = sym->visited;
 859                        sym->visited = NULL;
 860                }
 861        }
 862
 863        if (flag_debug) {
 864                fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
 865                        nsyms, HASH_BUCKETS,
 866                        (double)nsyms / (double)HASH_BUCKETS);
 867        }
 868
 869        if (dumpfile)
 870                fclose(dumpfile);
 871
 872        return errors != 0;
 873}
 874