home *** CD-ROM | disk | FTP | other *** search
- /* Generate kernel symbol version hashes.
- Copyright 1996, 1997 Linux International.
-
- New implementation contributed by Richard Henderson <rth@tamu.edu>
- Based on original work by Bjorn Eckwall <bj0rn@blox.se>
-
- This file is part of the Linux modutils.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2 of the License, or (at your
- option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
- #ident "$Id: genksyms.c,v 1.1.1.1 1998/01/06 20:51:07 ewt Exp $"
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <assert.h>
- #include <stdarg.h>
-
- #include "genksyms.h"
- #include "util.h"
- #include "version.h"
-
- /*----------------------------------------------------------------------*/
-
- #define HASH_BUCKETS 4099
-
- static struct symbol *symtab[HASH_BUCKETS];
- FILE *outfile, *debugfile;
-
- int cur_line = 1;
- char *cur_filename, *output_directory;
-
- int flag_debug, flag_dump_defs, flag_export_globals, flag_warnings;
- int checksum_version = 1, kernel_version = version(2,0,0);
-
- static int errors;
- static int nsyms;
-
- static struct symbol *expansion_trail;
- static const char *crc_prefix = "";
-
- static const char * const symbol_type_name[] = {
- "normal", "typedef", "enum", "struct", "union"
- };
-
- /*----------------------------------------------------------------------*/
-
- static const unsigned int crctab32[] =
- {
- #include "crc32.tab"
- };
-
- static inline unsigned long
- partial_crc32_one(unsigned char c, unsigned long crc)
- {
- return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
- }
-
- static inline unsigned long
- partial_crc32(const char *s, unsigned long crc)
- {
- while (*s)
- crc = partial_crc32_one(*s++, crc);
- return crc;
- }
-
- static inline unsigned long
- crc32(const char *s)
- {
- return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
- }
-
-
- /*----------------------------------------------------------------------*/
-
- static inline enum symbol_type
- map_to_ns(enum symbol_type t)
- {
- if (t == SYM_TYPEDEF)
- t = SYM_NORMAL;
- else if (t == SYM_UNION)
- t = SYM_STRUCT;
- return t;
- }
-
- struct symbol *
- find_symbol(const char *name, enum symbol_type ns)
- {
- unsigned long h = crc32(name) % HASH_BUCKETS;
- struct symbol *sym;
-
- for (sym = symtab[h]; sym ; sym = sym->hash_next)
- if (map_to_ns(sym->type) == map_to_ns(ns) && strcmp(name, sym->name) == 0)
- break;
-
- return sym;
- }
-
- struct symbol *
- add_symbol(const char *name, enum symbol_type type, struct string_list *defn)
- {
- unsigned long h = crc32(name) % HASH_BUCKETS;
- struct symbol *sym;
-
- for (sym = symtab[h]; sym ; sym = sym->hash_next)
- if (map_to_ns(sym->type) == map_to_ns(type)
- && strcmp(name, sym->name) == 0)
- {
- if (!equal_list(sym->defn, defn))
- error_with_pos("redefinition of %s", name);
- return sym;
- }
-
- sym = xmalloc(sizeof(*sym));
- sym->name = name;
- sym->type = type;
- sym->defn = defn;
- sym->expansion_trail = NULL;
-
- sym->hash_next = symtab[h];
- symtab[h] = sym;
-
- if (flag_debug)
- {
- fprintf(debugfile, "Defn for %s %s == <", symbol_type_name[type], name);
- print_list(debugfile, defn);
- fputs(">\n", debugfile);
- }
-
- ++nsyms;
- return sym;
- }
-
-
- /*----------------------------------------------------------------------*/
-
- inline void
- free_node(struct string_list *node)
- {
- free(node->string);
- free(node);
- }
-
- void
- free_list(struct string_list *s, struct string_list *e)
- {
- while (s != e)
- {
- struct string_list *next = s->next;
- free_node(s);
- s = next;
- }
- }
-
- inline struct string_list *
- copy_node(struct string_list *node)
- {
- struct string_list *newnode;
-
- newnode = xmalloc(sizeof(*newnode));
- newnode->string = xstrdup(node->string);
- newnode->tag = node->tag;
-
- return newnode;
- }
-
- struct string_list *
- copy_list(struct string_list *s, struct string_list *e)
- {
- struct string_list *h, *p;
-
- if (s == e)
- return NULL;
-
- p = h = copy_node(s);
- while ((s = s->next) != e)
- p = p->next = copy_node(s);
- p->next = NULL;
-
- return h;
- }
-
- int
- equal_list(struct string_list *a, struct string_list *b)
- {
- while (a && b)
- {
- if (a->tag != b->tag || strcmp(a->string, b->string))
- return 0;
- a = a->next;
- b = b->next;
- }
-
- return !a && !b;
- }
-
- static inline void
- print_node(FILE *f, struct string_list *list)
- {
- switch (list->tag)
- {
- case SYM_STRUCT:
- putc('s', f);
- goto printit;
- case SYM_UNION:
- putc('u', f);
- goto printit;
- case SYM_ENUM:
- putc('e', f);
- goto printit;
- case SYM_TYPEDEF:
- putc('t', f);
- goto printit;
-
- printit:
- putc('#', f);
- case SYM_NORMAL:
- fputs(list->string, f);
- break;
- }
- }
-
- void
- print_list(FILE *f, struct string_list *list)
- {
- struct string_list **e, **b;
- struct string_list *tmp, **tmp2;
- int elem = 1;
-
- if (list == NULL)
- {
- fputs("(nil)", f);
- return;
- }
-
- tmp = list;
- while((tmp = tmp->next) != NULL)
- elem++;
-
- b = alloca(elem * sizeof(*e));
- e = b + elem;
- tmp2 = e - 1;
-
- (*tmp2--) = list;
- while((list = list->next) != NULL)
- *(tmp2--) = list;
-
- while (b != e)
- {
- print_node(f, *b++);
- putc(' ', f);
- }
- }
-
- static unsigned long
- expand_and_crc_list(struct string_list *list, unsigned long crc)
- {
- struct string_list **e, **b;
- struct string_list *tmp, **tmp2;
- int elem = 1;
-
- if (!list)
- return crc;
-
- tmp = list;
- while((tmp = tmp->next) != NULL)
- elem++;
-
- b = alloca(elem * sizeof(*e));
- e = b + elem;
- tmp2 = e - 1;
-
- *(tmp2--) = list;
- while ((list = list->next) != NULL)
- *(tmp2--) = list;
-
- while (b != e)
- {
- struct string_list *cur;
- struct symbol *subsym;
-
- cur = *(b++);
- switch (cur->tag)
- {
- case SYM_NORMAL:
- if (flag_dump_defs)
- fprintf(debugfile, "%s ", cur->string);
- crc = partial_crc32(cur->string, crc);
- crc = partial_crc32_one(' ', crc);
- break;
-
- case SYM_TYPEDEF:
- subsym = find_symbol(cur->string, cur->tag);
- if (checksum_version == 1)
- crc = expand_and_crc_list(subsym->defn, crc);
- else if (subsym->expansion_trail)
- {
- if (flag_dump_defs)
- fprintf(debugfile, "%s ", cur->string);
- crc = partial_crc32(cur->string, crc);
- crc = partial_crc32_one(' ', crc);
- }
- else
- {
- subsym->expansion_trail = expansion_trail;
- expansion_trail = subsym;
- crc = expand_and_crc_list(subsym->defn, crc);
- }
- break;
-
- case SYM_STRUCT:
- case SYM_UNION:
- case SYM_ENUM:
- subsym = find_symbol(cur->string, cur->tag);
- if (!subsym)
- {
- struct string_list *n, *t = NULL;
-
- error_with_pos("expand undefined %s %s",
- symbol_type_name[cur->tag], cur->string);
-
- n = xmalloc(sizeof(*n));
- n->string = xstrdup(symbol_type_name[cur->tag]);
- n->tag = SYM_NORMAL;
- n->next = t;
- t = n;
-
- n = xmalloc(sizeof(*n));
- n->string = xstrdup(cur->string);
- n->tag = SYM_NORMAL;
- n->next = t;
- t = n;
-
- n = xmalloc(sizeof(*n));
- n->string = xstrdup("{ UNKNOWN }");
- n->tag = SYM_NORMAL;
- n->next = t;
-
- subsym = add_symbol(cur->string, cur->tag, n);
- }
- if (subsym->expansion_trail)
- {
- if (flag_dump_defs)
- {
- fprintf(debugfile, "%s %s ", symbol_type_name[cur->tag],
- cur->string);
- }
-
- crc = partial_crc32(symbol_type_name[cur->tag], crc);
- crc = partial_crc32_one(' ', crc);
- crc = partial_crc32(cur->string, crc);
- crc = partial_crc32_one(' ', crc);
- }
- else
- {
- subsym->expansion_trail = expansion_trail;
- expansion_trail = subsym;
- crc = expand_and_crc_list(subsym->defn, crc);
- }
- break;
- }
- }
-
- return crc;
- }
-
- void
- export_symbol(const char *name)
- {
- struct symbol *sym;
-
- sym = find_symbol(name, SYM_NORMAL);
- if (!sym)
- error_with_pos("export undefined symbol %s", name);
- else
- {
- unsigned long crc;
-
- if (flag_dump_defs)
- fprintf(debugfile, "Export %s == <", name);
-
- expansion_trail = (struct symbol *)-1L;
-
- crc = expand_and_crc_list(sym->defn, 0xffffffff) ^ 0xffffffff;
-
- sym = expansion_trail;
- while (sym != (struct symbol *)-1L)
- {
- struct symbol *n = sym->expansion_trail;
- sym->expansion_trail = 0;
- sym = n;
- }
-
- if (flag_dump_defs)
- fputs(">\n", debugfile);
-
- if (checksum_version > 1)
- {
- fprintf(outfile, "#define __ver_%s\t%s%08lx\n", name,
- crc_prefix, crc);
- fprintf(outfile, "#define %s\t_set_ver(%s)\n", name, name);
- }
- else
- {
- fprintf(outfile, "#define %s\t_set_ver(%s, %s%08lx)\n", name, name,
- crc_prefix, crc);
- }
- }
- }
-
-
- /*----------------------------------------------------------------------*/
-
- void
- error(const char *fmt, ...)
- {
- va_list args;
-
- if (flag_warnings)
- {
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- putc('\n', stderr);
-
- errors++;
- }
- }
-
- void
- error_with_pos(const char *fmt, ...)
- {
- va_list args;
-
- if (flag_warnings)
- {
- fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
-
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- putc('\n', stderr);
-
- errors++;
- }
- }
-
-
- int
- main(int argc, char **argv)
- {
- int o;
-
- while ((o = getopt(argc, argv, "dgwqVDk:p:")) != EOF)
- switch (o)
- {
- case 'd':
- flag_debug++;
- break;
- case 'g':
- flag_export_globals = 1;
- break;
- case 'w':
- flag_warnings = 1;
- break;
- case 'q':
- flag_warnings = 0;
- break;
- case 'V':
- fputs("genksyms version " MODUTILS_VERSION "\n", stderr);
- break;
- case 'D':
- flag_dump_defs = 1;
- break;
- case 'k':
- {
- char *p;
- int a, b, c;
-
- p = optarg;
- a = strtoul(p, &p, 10);
- if (*p != '.')
- return -1;
- b = strtoul(p+1, &p, 10);
- if (*p != '.')
- return -1;
- c = strtoul(p+1, &p, 10);
- if (*p != '\0')
- return -1;
-
- kernel_version = a << 16 | b << 8 | c;
- }
- break;
- case 'p':
- crc_prefix = optarg;
- break;
-
- default:
- usage:
- fputs("Usage:\n"
- "genksyms [-dDwqV] -k kernel_version > .../linux/module/*.ver\n"
- "\n"
- " -d Debug level -- repeat to increase\n"
- " -D Dump final exported definitions\n"
- " -w Enable warnings (aka errors)\n"
- " -q Disable warnings (default)\n"
- " -V Show version\n"
- " -k ver Set the kernel version for which we are compiling\n"
- " -p string Set a mangling prefix for all symbols\n"
- , stderr);
- return 1;
- }
-
- if (kernel_version >= version(2,1,18))
- {
- if (optind != argc)
- goto usage;
-
- /* Exporting all globals is depreciated. */
- if (flag_export_globals)
- goto usage;
-
- /* For newer kernels, eliminate some irrelevant constructs. */
- checksum_version = 2;
-
- outfile = stdout;
- }
- else
- {
- if (optind+1 != argc)
- goto usage;
- output_directory = argv[optind];
- }
-
- {
- extern int yydebug;
- extern int yy_flex_debug;
-
- yydebug = (flag_debug > 1);
- yy_flex_debug = (flag_debug > 2);
-
- debugfile = stderr;
- /* setlinebuf(debugfile); */
- }
-
- yyparse();
-
- if (flag_export_globals)
- {
- /* FIXME */
- }
-
- if (checksum_version == 1)
- {
- fputs("#endif\n#endif\n", outfile);
- }
-
- if (flag_debug)
- {
- fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
- nsyms, HASH_BUCKETS, (double)nsyms / (double)HASH_BUCKETS);
- }
-
- return errors != 0;
- }
-