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, flag_rel_crcs;
  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, in_string = 0;
 427
 428        while ((c = fgetc(f)) != EOF) {
 429                if (!in_string && c == ' ') {
 430                        if (node.string == buffer)
 431                                continue;
 432                        break;
 433                } else if (c == '"') {
 434                        in_string = !in_string;
 435                } else if (c == '\n') {
 436                        if (node.string == buffer)
 437                                return NULL;
 438                        ungetc(c, f);
 439                        break;
 440                }
 441                if (node.string >= buffer + sizeof(buffer) - 1) {
 442                        fprintf(stderr, "Token too long\n");
 443                        exit(1);
 444                }
 445                *node.string++ = c;
 446        }
 447        if (node.string == buffer)
 448                return NULL;
 449        *node.string = 0;
 450        node.string = buffer;
 451
 452        if (node.string[1] == '#') {
 453                size_t n;
 454
 455                for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
 456                        if (node.string[0] == symbol_types[n].n) {
 457                                node.tag = n;
 458                                node.string += 2;
 459                                return copy_node(&node);
 460                        }
 461                }
 462                fprintf(stderr, "Unknown type %c\n", node.string[0]);
 463                exit(1);
 464        }
 465        return copy_node(&node);
 466}
 467
 468static void read_reference(FILE *f)
 469{
 470        while (!feof(f)) {
 471                struct string_list *defn = NULL;
 472                struct string_list *sym, *def;
 473                int is_extern = 0, is_override = 0;
 474                struct symbol *subsym;
 475
 476                sym = read_node(f);
 477                if (sym && sym->tag == SYM_NORMAL &&
 478                    !strcmp(sym->string, "override")) {
 479                        is_override = 1;
 480                        free_node(sym);
 481                        sym = read_node(f);
 482                }
 483                if (!sym)
 484                        continue;
 485                def = read_node(f);
 486                if (def && def->tag == SYM_NORMAL &&
 487                    !strcmp(def->string, "extern")) {
 488                        is_extern = 1;
 489                        free_node(def);
 490                        def = read_node(f);
 491                }
 492                while (def) {
 493                        def->next = defn;
 494                        defn = def;
 495                        def = read_node(f);
 496                }
 497                subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
 498                                              defn, is_extern);
 499                subsym->is_override = is_override;
 500                free_node(sym);
 501        }
 502}
 503
 504static void print_node(FILE * f, struct string_list *list)
 505{
 506        if (symbol_types[list->tag].n) {
 507                putc(symbol_types[list->tag].n, f);
 508                putc('#', f);
 509        }
 510        fputs(list->string, f);
 511}
 512
 513static void print_list(FILE * f, struct string_list *list)
 514{
 515        struct string_list **e, **b;
 516        struct string_list *tmp, **tmp2;
 517        int elem = 1;
 518
 519        if (list == NULL) {
 520                fputs("(nil)", f);
 521                return;
 522        }
 523
 524        tmp = list;
 525        while ((tmp = tmp->next) != NULL)
 526                elem++;
 527
 528        b = alloca(elem * sizeof(*e));
 529        e = b + elem;
 530        tmp2 = e - 1;
 531
 532        (*tmp2--) = list;
 533        while ((list = list->next) != NULL)
 534                *(tmp2--) = list;
 535
 536        while (b != e) {
 537                print_node(f, *b++);
 538                putc(' ', f);
 539        }
 540}
 541
 542static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
 543{
 544        struct string_list *list = sym->defn;
 545        struct string_list **e, **b;
 546        struct string_list *tmp, **tmp2;
 547        int elem = 1;
 548
 549        if (!list)
 550                return crc;
 551
 552        tmp = list;
 553        while ((tmp = tmp->next) != NULL)
 554                elem++;
 555
 556        b = alloca(elem * sizeof(*e));
 557        e = b + elem;
 558        tmp2 = e - 1;
 559
 560        *(tmp2--) = list;
 561        while ((list = list->next) != NULL)
 562                *(tmp2--) = list;
 563
 564        while (b != e) {
 565                struct string_list *cur;
 566                struct symbol *subsym;
 567
 568                cur = *(b++);
 569                switch (cur->tag) {
 570                case SYM_NORMAL:
 571                        if (flag_dump_defs)
 572                                fprintf(debugfile, "%s ", cur->string);
 573                        crc = partial_crc32(cur->string, crc);
 574                        crc = partial_crc32_one(' ', crc);
 575                        break;
 576
 577                case SYM_ENUM_CONST:
 578                case SYM_TYPEDEF:
 579                        subsym = find_symbol(cur->string, cur->tag, 0);
 580                        /* FIXME: Bad reference files can segfault here. */
 581                        if (subsym->expansion_trail) {
 582                                if (flag_dump_defs)
 583                                        fprintf(debugfile, "%s ", cur->string);
 584                                crc = partial_crc32(cur->string, crc);
 585                                crc = partial_crc32_one(' ', crc);
 586                        } else {
 587                                subsym->expansion_trail = expansion_trail;
 588                                expansion_trail = subsym;
 589                                crc = expand_and_crc_sym(subsym, crc);
 590                        }
 591                        break;
 592
 593                case SYM_STRUCT:
 594                case SYM_UNION:
 595                case SYM_ENUM:
 596                        subsym = find_symbol(cur->string, cur->tag, 0);
 597                        if (!subsym) {
 598                                struct string_list *n;
 599
 600                                error_with_pos("expand undefined %s %s",
 601                                               symbol_types[cur->tag].name,
 602                                               cur->string);
 603                                n = concat_list(mk_node
 604                                                (symbol_types[cur->tag].name),
 605                                                mk_node(cur->string),
 606                                                mk_node("{"),
 607                                                mk_node("UNKNOWN"),
 608                                                mk_node("}"), NULL);
 609                                subsym =
 610                                    add_symbol(cur->string, cur->tag, n, 0);
 611                        }
 612                        if (subsym->expansion_trail) {
 613                                if (flag_dump_defs) {
 614                                        fprintf(debugfile, "%s %s ",
 615                                                symbol_types[cur->tag].name,
 616                                                cur->string);
 617                                }
 618
 619                                crc = partial_crc32(symbol_types[cur->tag].name,
 620                                                    crc);
 621                                crc = partial_crc32_one(' ', crc);
 622                                crc = partial_crc32(cur->string, crc);
 623                                crc = partial_crc32_one(' ', crc);
 624                        } else {
 625                                subsym->expansion_trail = expansion_trail;
 626                                expansion_trail = subsym;
 627                                crc = expand_and_crc_sym(subsym, crc);
 628                        }
 629                        break;
 630                }
 631        }
 632
 633        {
 634                static struct symbol **end = &visited_symbols;
 635
 636                if (!sym->visited) {
 637                        *end = sym;
 638                        end = &sym->visited;
 639                        sym->visited = (struct symbol *)-1L;
 640                }
 641        }
 642
 643        return crc;
 644}
 645
 646void export_symbol(const char *name)
 647{
 648        struct symbol *sym;
 649
 650        sym = find_symbol(name, SYM_NORMAL, 0);
 651        if (!sym)
 652                error_with_pos("export undefined symbol %s", name);
 653        else {
 654                unsigned long crc;
 655                int has_changed = 0;
 656
 657                if (flag_dump_defs)
 658                        fprintf(debugfile, "Export %s == <", name);
 659
 660                expansion_trail = (struct symbol *)-1L;
 661
 662                sym->expansion_trail = expansion_trail;
 663                expansion_trail = sym;
 664                crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
 665
 666                sym = expansion_trail;
 667                while (sym != (struct symbol *)-1L) {
 668                        struct symbol *n = sym->expansion_trail;
 669
 670                        if (sym->status != STATUS_UNCHANGED) {
 671                                if (!has_changed) {
 672                                        print_location();
 673                                        fprintf(stderr, "%s: %s: modversion "
 674                                                "changed because of changes "
 675                                                "in ", flag_preserve ? "error" :
 676                                                       "warning", name);
 677                                } else
 678                                        fprintf(stderr, ", ");
 679                                print_type_name(sym->type, sym->name);
 680                                if (sym->status == STATUS_DEFINED)
 681                                        fprintf(stderr, " (became defined)");
 682                                has_changed = 1;
 683                                if (flag_preserve)
 684                                        errors++;
 685                        }
 686                        sym->expansion_trail = 0;
 687                        sym = n;
 688                }
 689                if (has_changed)
 690                        fprintf(stderr, "\n");
 691
 692                if (flag_dump_defs)
 693                        fputs(">\n", debugfile);
 694
 695                /* Used as a linker script. */
 696                printf(!flag_rel_crcs ? "%s__crc_%s = 0x%08lx;\n" :
 697                       "SECTIONS { .rodata : ALIGN(4) { "
 698                       "%s__crc_%s = .; LONG(0x%08lx); } }\n",
 699                       mod_prefix, name, crc);
 700        }
 701}
 702
 703/*----------------------------------------------------------------------*/
 704
 705static void print_location(void)
 706{
 707        fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
 708}
 709
 710static void print_type_name(enum symbol_type type, const char *name)
 711{
 712        if (symbol_types[type].name)
 713                fprintf(stderr, "%s %s", symbol_types[type].name, name);
 714        else
 715                fprintf(stderr, "%s", name);
 716}
 717
 718void error_with_pos(const char *fmt, ...)
 719{
 720        va_list args;
 721
 722        if (flag_warnings) {
 723                print_location();
 724
 725                va_start(args, fmt);
 726                vfprintf(stderr, fmt, args);
 727                va_end(args);
 728                putc('\n', stderr);
 729
 730                errors++;
 731        }
 732}
 733
 734static void genksyms_usage(void)
 735{
 736        fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
 737#ifdef __GNU_LIBRARY__
 738              "  -s, --symbol-prefix   Select symbol prefix\n"
 739              "  -d, --debug           Increment the debug level (repeatable)\n"
 740              "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
 741              "  -r, --reference file  Read reference symbols from a file\n"
 742              "  -T, --dump-types file Dump expanded types into file\n"
 743              "  -p, --preserve        Preserve reference modversions or fail\n"
 744              "  -w, --warnings        Enable warnings\n"
 745              "  -q, --quiet           Disable warnings (default)\n"
 746              "  -h, --help            Print this message\n"
 747              "  -V, --version         Print the release version\n"
 748              "  -R, --relative-crc    Emit section relative symbol CRCs\n"
 749#else                           /* __GNU_LIBRARY__ */
 750              "  -s                    Select symbol prefix\n"
 751              "  -d                    Increment the debug level (repeatable)\n"
 752              "  -D                    Dump expanded symbol defs (for debugging only)\n"
 753              "  -r file               Read reference symbols from a file\n"
 754              "  -T file               Dump expanded types into file\n"
 755              "  -p                    Preserve reference modversions or fail\n"
 756              "  -w                    Enable warnings\n"
 757              "  -q                    Disable warnings (default)\n"
 758              "  -h                    Print this message\n"
 759              "  -V                    Print the release version\n"
 760              "  -R                    Emit section relative symbol CRCs\n"
 761#endif                          /* __GNU_LIBRARY__ */
 762              , stderr);
 763}
 764
 765int main(int argc, char **argv)
 766{
 767        FILE *dumpfile = NULL, *ref_file = NULL;
 768        int o;
 769
 770#ifdef __GNU_LIBRARY__
 771        struct option long_opts[] = {
 772                {"symbol-prefix", 1, 0, 's'},
 773                {"debug", 0, 0, 'd'},
 774                {"warnings", 0, 0, 'w'},
 775                {"quiet", 0, 0, 'q'},
 776                {"dump", 0, 0, 'D'},
 777                {"reference", 1, 0, 'r'},
 778                {"dump-types", 1, 0, 'T'},
 779                {"preserve", 0, 0, 'p'},
 780                {"version", 0, 0, 'V'},
 781                {"help", 0, 0, 'h'},
 782                {"relative-crc", 0, 0, 'R'},
 783                {0, 0, 0, 0}
 784        };
 785
 786        while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
 787                                &long_opts[0], NULL)) != EOF)
 788#else                           /* __GNU_LIBRARY__ */
 789        while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
 790#endif                          /* __GNU_LIBRARY__ */
 791                switch (o) {
 792                case 's':
 793                        mod_prefix = optarg;
 794                        break;
 795                case 'd':
 796                        flag_debug++;
 797                        break;
 798                case 'w':
 799                        flag_warnings = 1;
 800                        break;
 801                case 'q':
 802                        flag_warnings = 0;
 803                        break;
 804                case 'V':
 805                        fputs("genksyms version 2.5.60\n", stderr);
 806                        break;
 807                case 'D':
 808                        flag_dump_defs = 1;
 809                        break;
 810                case 'r':
 811                        flag_reference = 1;
 812                        ref_file = fopen(optarg, "r");
 813                        if (!ref_file) {
 814                                perror(optarg);
 815                                return 1;
 816                        }
 817                        break;
 818                case 'T':
 819                        flag_dump_types = 1;
 820                        dumpfile = fopen(optarg, "w");
 821                        if (!dumpfile) {
 822                                perror(optarg);
 823                                return 1;
 824                        }
 825                        break;
 826                case 'p':
 827                        flag_preserve = 1;
 828                        break;
 829                case 'h':
 830                        genksyms_usage();
 831                        return 0;
 832                case 'R':
 833                        flag_rel_crcs = 1;
 834                        break;
 835                default:
 836                        genksyms_usage();
 837                        return 1;
 838                }
 839        {
 840                extern int yydebug;
 841                extern int yy_flex_debug;
 842
 843                yydebug = (flag_debug > 1);
 844                yy_flex_debug = (flag_debug > 2);
 845
 846                debugfile = stderr;
 847                /* setlinebuf(debugfile); */
 848        }
 849
 850        if (flag_reference) {
 851                read_reference(ref_file);
 852                fclose(ref_file);
 853        }
 854
 855        yyparse();
 856
 857        if (flag_dump_types && visited_symbols) {
 858                while (visited_symbols != (struct symbol *)-1L) {
 859                        struct symbol *sym = visited_symbols;
 860
 861                        if (sym->is_override)
 862                                fputs("override ", dumpfile);
 863                        if (symbol_types[sym->type].n) {
 864                                putc(symbol_types[sym->type].n, dumpfile);
 865                                putc('#', dumpfile);
 866                        }
 867                        fputs(sym->name, dumpfile);
 868                        putc(' ', dumpfile);
 869                        if (sym->is_extern)
 870                                fputs("extern ", dumpfile);
 871                        print_list(dumpfile, sym->defn);
 872                        putc('\n', dumpfile);
 873
 874                        visited_symbols = sym->visited;
 875                        sym->visited = NULL;
 876                }
 877        }
 878
 879        if (flag_debug) {
 880                fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
 881                        nsyms, HASH_BUCKETS,
 882                        (double)nsyms / (double)HASH_BUCKETS);
 883        }
 884
 885        if (dumpfile)
 886                fclose(dumpfile);
 887
 888        return errors != 0;
 889}
 890