linux/scripts/genksyms/genksyms.c
<<
>>
Prefs
   1/* Generate kernel symbol version hashes.
   2   Copyright 1996, 1997 Linux International.
   3
   4   New implementation contributed by Richard Henderson <rth@tamu.edu>
   5   Based on original work by Bjorn Ekwall <bj0rn@blox.se>
   6
   7   This file was part of the Linux modutils 2.4.22: moved back into the
   8   kernel sources by Rusty Russell/Kai Germaschewski.
   9
  10   This program is free software; you can redistribute it and/or modify it
  11   under the terms of the GNU General Public License as published by the
  12   Free Software Foundation; either version 2 of the License, or (at your
  13   option) any later version.
  14
  15   This program is distributed in the hope that it will be useful, but
  16   WITHOUT ANY WARRANTY; without even the implied warranty of
  17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18   General Public License for more details.
  19
  20   You should have received a copy of the GNU General Public License
  21   along with this program; if not, write to the Free Software Foundation,
  22   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  23
  24#include <stdio.h>
  25#include <string.h>
  26#include <stdlib.h>
  27#include <unistd.h>
  28#include <assert.h>
  29#include <stdarg.h>
  30#ifdef __GNU_LIBRARY__
  31#include <getopt.h>
  32#endif                          /* __GNU_LIBRARY__ */
  33
  34#include "genksyms.h"
  35/*----------------------------------------------------------------------*/
  36
  37#define HASH_BUCKETS  4096
  38
  39static struct symbol *symtab[HASH_BUCKETS];
  40static FILE *debugfile;
  41
  42int cur_line = 1;
  43char *cur_filename;
  44
  45static int flag_debug, flag_dump_defs, flag_dump_types, flag_warnings;
  46static const char *arch = "";
  47static const char *mod_prefix = "";
  48
  49static int errors;
  50static int nsyms;
  51
  52static struct symbol *expansion_trail;
  53static struct symbol *visited_symbols;
  54
  55static const char *const symbol_type_name[] = {
  56        "normal", "typedef", "enum", "struct", "union"
  57};
  58
  59static int equal_list(struct string_list *a, struct string_list *b);
  60static void print_list(FILE * f, struct string_list *list);
  61
  62/*----------------------------------------------------------------------*/
  63
  64static const unsigned int crctab32[] = {
  65        0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
  66        0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
  67        0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
  68        0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
  69        0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
  70        0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
  71        0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
  72        0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
  73        0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
  74        0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
  75        0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
  76        0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
  77        0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
  78        0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
  79        0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
  80        0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
  81        0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
  82        0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
  83        0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
  84        0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
  85        0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
  86        0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
  87        0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
  88        0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
  89        0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
  90        0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
  91        0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
  92        0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
  93        0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
  94        0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
  95        0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
  96        0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
  97        0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
  98        0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
  99        0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
 100        0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
 101        0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
 102        0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
 103        0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
 104        0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
 105        0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
 106        0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
 107        0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
 108        0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
 109        0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
 110        0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
 111        0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
 112        0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
 113        0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
 114        0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
 115        0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
 116        0x2d02ef8dU
 117};
 118
 119static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
 120{
 121        return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
 122}
 123
 124static unsigned long partial_crc32(const char *s, unsigned long crc)
 125{
 126        while (*s)
 127                crc = partial_crc32_one(*s++, crc);
 128        return crc;
 129}
 130
 131static unsigned long crc32(const char *s)
 132{
 133        return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
 134}
 135
 136/*----------------------------------------------------------------------*/
 137
 138static enum symbol_type map_to_ns(enum symbol_type t)
 139{
 140        if (t == SYM_TYPEDEF)
 141                t = SYM_NORMAL;
 142        else if (t == SYM_UNION)
 143                t = SYM_STRUCT;
 144        return t;
 145}
 146
 147struct symbol *find_symbol(const char *name, enum symbol_type ns)
 148{
 149        unsigned long h = crc32(name) % HASH_BUCKETS;
 150        struct symbol *sym;
 151
 152        for (sym = symtab[h]; sym; sym = sym->hash_next)
 153                if (map_to_ns(sym->type) == map_to_ns(ns) &&
 154                    strcmp(name, sym->name) == 0)
 155                        break;
 156
 157        return sym;
 158}
 159
 160struct symbol *add_symbol(const char *name, enum symbol_type type,
 161                          struct string_list *defn, int is_extern)
 162{
 163        unsigned long h = crc32(name) % HASH_BUCKETS;
 164        struct symbol *sym;
 165
 166        for (sym = symtab[h]; sym; sym = sym->hash_next) {
 167                if (map_to_ns(sym->type) == map_to_ns(type)
 168                    && strcmp(name, sym->name) == 0) {
 169                        if (!equal_list(sym->defn, defn))
 170                                error_with_pos("redefinition of %s", name);
 171                        return sym;
 172                }
 173        }
 174
 175        sym = xmalloc(sizeof(*sym));
 176        sym->name = name;
 177        sym->type = type;
 178        sym->defn = defn;
 179        sym->expansion_trail = NULL;
 180        sym->visited = NULL;
 181        sym->is_extern = is_extern;
 182
 183        sym->hash_next = symtab[h];
 184        symtab[h] = sym;
 185
 186        if (flag_debug) {
 187                fprintf(debugfile, "Defn for %s %s == <",
 188                        symbol_type_name[type], name);
 189                if (is_extern)
 190                        fputs("extern ", debugfile);
 191                print_list(debugfile, defn);
 192                fputs(">\n", debugfile);
 193        }
 194
 195        ++nsyms;
 196        return sym;
 197}
 198
 199/*----------------------------------------------------------------------*/
 200
 201void free_node(struct string_list *node)
 202{
 203        free(node->string);
 204        free(node);
 205}
 206
 207void free_list(struct string_list *s, struct string_list *e)
 208{
 209        while (s != e) {
 210                struct string_list *next = s->next;
 211                free_node(s);
 212                s = next;
 213        }
 214}
 215
 216struct string_list *copy_node(struct string_list *node)
 217{
 218        struct string_list *newnode;
 219
 220        newnode = xmalloc(sizeof(*newnode));
 221        newnode->string = xstrdup(node->string);
 222        newnode->tag = node->tag;
 223
 224        return newnode;
 225}
 226
 227static int equal_list(struct string_list *a, struct string_list *b)
 228{
 229        while (a && b) {
 230                if (a->tag != b->tag || strcmp(a->string, b->string))
 231                        return 0;
 232                a = a->next;
 233                b = b->next;
 234        }
 235
 236        return !a && !b;
 237}
 238
 239static void print_node(FILE * f, struct string_list *list)
 240{
 241        if (list->tag != SYM_NORMAL) {
 242                putc(symbol_type_name[list->tag][0], f);
 243                putc('#', f);
 244        }
 245        fputs(list->string, f);
 246}
 247
 248static void print_list(FILE * f, struct string_list *list)
 249{
 250        struct string_list **e, **b;
 251        struct string_list *tmp, **tmp2;
 252        int elem = 1;
 253
 254        if (list == NULL) {
 255                fputs("(nil)", f);
 256                return;
 257        }
 258
 259        tmp = list;
 260        while ((tmp = tmp->next) != NULL)
 261                elem++;
 262
 263        b = alloca(elem * sizeof(*e));
 264        e = b + elem;
 265        tmp2 = e - 1;
 266
 267        (*tmp2--) = list;
 268        while ((list = list->next) != NULL)
 269                *(tmp2--) = list;
 270
 271        while (b != e) {
 272                print_node(f, *b++);
 273                putc(' ', f);
 274        }
 275}
 276
 277static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
 278{
 279        struct string_list *list = sym->defn;
 280        struct string_list **e, **b;
 281        struct string_list *tmp, **tmp2;
 282        int elem = 1;
 283
 284        if (!list)
 285                return crc;
 286
 287        tmp = list;
 288        while ((tmp = tmp->next) != NULL)
 289                elem++;
 290
 291        b = alloca(elem * sizeof(*e));
 292        e = b + elem;
 293        tmp2 = e - 1;
 294
 295        *(tmp2--) = list;
 296        while ((list = list->next) != NULL)
 297                *(tmp2--) = list;
 298
 299        while (b != e) {
 300                struct string_list *cur;
 301                struct symbol *subsym;
 302
 303                cur = *(b++);
 304                switch (cur->tag) {
 305                case SYM_NORMAL:
 306                        if (flag_dump_defs)
 307                                fprintf(debugfile, "%s ", cur->string);
 308                        crc = partial_crc32(cur->string, crc);
 309                        crc = partial_crc32_one(' ', crc);
 310                        break;
 311
 312                case SYM_TYPEDEF:
 313                        subsym = find_symbol(cur->string, cur->tag);
 314                        if (subsym->expansion_trail) {
 315                                if (flag_dump_defs)
 316                                        fprintf(debugfile, "%s ", cur->string);
 317                                crc = partial_crc32(cur->string, crc);
 318                                crc = partial_crc32_one(' ', crc);
 319                        } else {
 320                                subsym->expansion_trail = expansion_trail;
 321                                expansion_trail = subsym;
 322                                crc = expand_and_crc_sym(subsym, crc);
 323                        }
 324                        break;
 325
 326                case SYM_STRUCT:
 327                case SYM_UNION:
 328                case SYM_ENUM:
 329                        subsym = find_symbol(cur->string, cur->tag);
 330                        if (!subsym) {
 331                                struct string_list *n, *t = NULL;
 332
 333                                error_with_pos("expand undefined %s %s",
 334                                               symbol_type_name[cur->tag],
 335                                               cur->string);
 336
 337                                n = xmalloc(sizeof(*n));
 338                                n->string = xstrdup(symbol_type_name[cur->tag]);
 339                                n->tag = SYM_NORMAL;
 340                                n->next = t;
 341                                t = n;
 342
 343                                n = xmalloc(sizeof(*n));
 344                                n->string = xstrdup(cur->string);
 345                                n->tag = SYM_NORMAL;
 346                                n->next = t;
 347                                t = n;
 348
 349                                n = xmalloc(sizeof(*n));
 350                                n->string = xstrdup("{ UNKNOWN }");
 351                                n->tag = SYM_NORMAL;
 352                                n->next = t;
 353
 354                                subsym =
 355                                    add_symbol(cur->string, cur->tag, n, 0);
 356                        }
 357                        if (subsym->expansion_trail) {
 358                                if (flag_dump_defs) {
 359                                        fprintf(debugfile, "%s %s ",
 360                                                symbol_type_name[cur->tag],
 361                                                cur->string);
 362                                }
 363
 364                                crc = partial_crc32(symbol_type_name[cur->tag],
 365                                                    crc);
 366                                crc = partial_crc32_one(' ', crc);
 367                                crc = partial_crc32(cur->string, crc);
 368                                crc = partial_crc32_one(' ', crc);
 369                        } else {
 370                                subsym->expansion_trail = expansion_trail;
 371                                expansion_trail = subsym;
 372                                crc = expand_and_crc_sym(subsym, crc);
 373                        }
 374                        break;
 375                }
 376        }
 377
 378        {
 379                static struct symbol **end = &visited_symbols;
 380
 381                if (!sym->visited) {
 382                        *end = sym;
 383                        end = &sym->visited;
 384                        sym->visited = (struct symbol *)-1L;
 385                }
 386        }
 387
 388        return crc;
 389}
 390
 391void export_symbol(const char *name)
 392{
 393        struct symbol *sym;
 394
 395        sym = find_symbol(name, SYM_NORMAL);
 396        if (!sym)
 397                error_with_pos("export undefined symbol %s", name);
 398        else {
 399                unsigned long crc;
 400
 401                if (flag_dump_defs)
 402                        fprintf(debugfile, "Export %s == <", name);
 403
 404                expansion_trail = (struct symbol *)-1L;
 405
 406                crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
 407
 408                sym = expansion_trail;
 409                while (sym != (struct symbol *)-1L) {
 410                        struct symbol *n = sym->expansion_trail;
 411                        sym->expansion_trail = 0;
 412                        sym = n;
 413                }
 414
 415                if (flag_dump_defs)
 416                        fputs(">\n", debugfile);
 417
 418                /* Used as a linker script. */
 419                printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
 420        }
 421}
 422
 423/*----------------------------------------------------------------------*/
 424void error_with_pos(const char *fmt, ...)
 425{
 426        va_list args;
 427
 428        if (flag_warnings) {
 429                fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>",
 430                        cur_line);
 431
 432                va_start(args, fmt);
 433                vfprintf(stderr, fmt, args);
 434                va_end(args);
 435                putc('\n', stderr);
 436
 437                errors++;
 438        }
 439}
 440
 441static void genksyms_usage(void)
 442{
 443        fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
 444#ifdef __GNU_LIBRARY__
 445              "  -a, --arch            Select architecture\n"
 446              "  -d, --debug           Increment the debug level (repeatable)\n"
 447              "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
 448              "  -T, --dump-types file Dump expanded types into file (for debugging only)\n"
 449              "  -w, --warnings        Enable warnings\n"
 450              "  -q, --quiet           Disable warnings (default)\n"
 451              "  -h, --help            Print this message\n"
 452              "  -V, --version         Print the release version\n"
 453#else                           /* __GNU_LIBRARY__ */
 454              "  -a                    Select architecture\n"
 455              "  -d                    Increment the debug level (repeatable)\n"
 456              "  -D                    Dump expanded symbol defs (for debugging only)\n"
 457              "  -T file               Dump expanded types into file (for debugging only)\n"
 458              "  -w                    Enable warnings\n"
 459              "  -q                    Disable warnings (default)\n"
 460              "  -h                    Print this message\n"
 461              "  -V                    Print the release version\n"
 462#endif                          /* __GNU_LIBRARY__ */
 463              , stderr);
 464}
 465
 466int main(int argc, char **argv)
 467{
 468        FILE *dumpfile = NULL;
 469        int o;
 470
 471#ifdef __GNU_LIBRARY__
 472        struct option long_opts[] = {
 473                {"arch", 1, 0, 'a'},
 474                {"debug", 0, 0, 'd'},
 475                {"warnings", 0, 0, 'w'},
 476                {"quiet", 0, 0, 'q'},
 477                {"dump", 0, 0, 'D'},
 478                {"dump-types", 1, 0, 'T'},
 479                {"version", 0, 0, 'V'},
 480                {"help", 0, 0, 'h'},
 481                {0, 0, 0, 0}
 482        };
 483
 484        while ((o = getopt_long(argc, argv, "a:dwqVDT:h",
 485                                &long_opts[0], NULL)) != EOF)
 486#else                           /* __GNU_LIBRARY__ */
 487        while ((o = getopt(argc, argv, "a:dwqVDT:h")) != EOF)
 488#endif                          /* __GNU_LIBRARY__ */
 489                switch (o) {
 490                case 'a':
 491                        arch = optarg;
 492                        break;
 493                case 'd':
 494                        flag_debug++;
 495                        break;
 496                case 'w':
 497                        flag_warnings = 1;
 498                        break;
 499                case 'q':
 500                        flag_warnings = 0;
 501                        break;
 502                case 'V':
 503                        fputs("genksyms version 2.5.60\n", stderr);
 504                        break;
 505                case 'D':
 506                        flag_dump_defs = 1;
 507                        break;
 508                case 'T':
 509                        flag_dump_types = 1;
 510                        dumpfile = fopen(optarg, "w");
 511                        if (!dumpfile) {
 512                                perror(optarg);
 513                                return 1;
 514                        }
 515                        break;
 516                case 'h':
 517                        genksyms_usage();
 518                        return 0;
 519                default:
 520                        genksyms_usage();
 521                        return 1;
 522                }
 523        if ((strcmp(arch, "h8300") == 0) || (strcmp(arch, "blackfin") == 0))
 524                mod_prefix = "_";
 525        {
 526                extern int yydebug;
 527                extern int yy_flex_debug;
 528
 529                yydebug = (flag_debug > 1);
 530                yy_flex_debug = (flag_debug > 2);
 531
 532                debugfile = stderr;
 533                /* setlinebuf(debugfile); */
 534        }
 535
 536        yyparse();
 537
 538        if (flag_dump_types && visited_symbols) {
 539                while (visited_symbols != (struct symbol *)-1L) {
 540                        struct symbol *sym = visited_symbols;
 541
 542                        if (sym->type != SYM_NORMAL) {
 543                                putc(symbol_type_name[sym->type][0], dumpfile);
 544                                putc('#', dumpfile);
 545                        }
 546                        fputs(sym->name, dumpfile);
 547                        putc(' ', dumpfile);
 548                        if (sym->is_extern)
 549                                fputs("extern ", dumpfile);
 550                        print_list(dumpfile, sym->defn);
 551                        putc('\n', dumpfile);
 552
 553                        visited_symbols = sym->visited;
 554                        sym->visited = NULL;
 555                }
 556        }
 557
 558        if (flag_debug) {
 559                fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
 560                        nsyms, HASH_BUCKETS,
 561                        (double)nsyms / (double)HASH_BUCKETS);
 562        }
 563
 564        return errors != 0;
 565}
 566