2 * Copyright (c) 1997 John D. Polstra.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/usr.bin/gensetdefs/gensetdefs.c,v 1.4 1999/12/12 21:16:46 marcel Exp $
27 * $DragonFly: src/usr.bin/gensetdefs/Attic/gensetdefs.c,v 1.2 2003/06/17 04:29:27 dillon Exp $
30 #include <sys/types.h>
31 #if defined(arch_i386)
32 #define __ELF_WORD_SIZE 32
33 #include <sys/elf32.h>
34 #elif defined(arch_alpha)
35 #define __ELF_WORD_SIZE 64
36 #include <sys/elf64.h>
38 #include <sys/elf_generic.h>
46 #define HASHSIZE 1009u /* Number of hash chains. */
47 #define PREFIX ".set." /* Section name prefix for linker sets. */
49 /* One entry in the hash table. */
50 typedef struct hashent {
51 struct hashent *next; /* Next entry with the same hash. */
52 char *name; /* Name of the linker set. */
53 size_t size; /* Size in bytes. */
56 /* Allocate storage for "count" objects of type "type". */
57 #define NEW(type, count) ((type *) xmalloc((count) * sizeof(type)))
59 static hashent *hashtab[HASHSIZE]; /* Hash chain heads. */
61 static void enter(const char *, size_t);
62 static int enter_sets(const char *);
63 static unsigned int hash(const char *);
64 static hashent *merge(void);
65 static int my_byte_order(void);
66 static void *xmalloc(size_t);
67 static char *xstrdup(const char *);
70 * This is a special-purpose program to generate the linker set definitions
71 * needed when building an ELF kernel. Its arguments are the names of
72 * ELF object files. It scans the section names of the object files,
73 * building a table of those that begin with ".set.", which represent
74 * linker sets. Finally, for each set "foo" with "count" elements, it
75 * writes a line "DEFINE_SET(foo, count);" to the standard output.
78 main(int argc, char **argv)
81 int status = EXIT_SUCCESS;
87 for (i = 1; i < argc; i++)
88 if (enter_sets(argv[i]) == -1)
89 status = EXIT_FAILURE;
91 fp = fopen("setdefs.h", "w");
95 while (list != NULL) {
98 fprintf(fp, "DEFINE_SET(%s, %lu);\n", list->name,
99 (unsigned long) (list->size / sizeof (void *)));
107 #if defined(arch_i386)
110 #elif defined(arch_alpha)
115 errx(1, "unknown architecture");
117 fp = fopen("setdef0.c", "w");
121 fprintf(fp, "/* THIS FILE IS GENERATED, DO NOT EDIT. */\n\n");
123 #define DEFINE_SET(set, count) \\\n\
124 __asm__(\".section .set.\" #set \",\\\"aw\\\"\"); \\\n\
125 __asm__(\".globl \" #set); \\\n\
126 __asm__(\".type \" #set \",@object\"); \\\n\
127 __asm__(\".p2align %d\"); \\\n\
128 __asm__(#set \":\"); \\\n\
129 __asm__(\".%s \" #count); \\\n\
130 __asm__(\".previous\")\n\
132 #include \"setdefs.h\" /* Contains a `DEFINE_SET' for each set */\n\
137 fp = fopen("setdef1.c", "w");
141 fprintf(fp, "/* THIS FILE IS GENERATED, DO NOT EDIT. */\n\n");
143 #define DEFINE_SET(set, count) \\\n\
144 __asm__(\".section .set.\" #set \",\\\"aw\\\"\"); \\\n\
145 __asm__(\".%s 0\"); \\\n\
146 __asm__(\".previous\")\n\
148 #include \"setdefs.h\" /* Contains a `DEFINE_SET' for each set */\n\
157 * Enter the given string into the hash table, if it is not already there.
158 * Each hash chain is kept sorted, so that it will be easy to merge the
159 * chains to get a single sorted list.
162 enter(const char *name, size_t size)
169 linkp = &hashtab[hash(name) % HASHSIZE];
170 while ((entp = *linkp) != NULL && (c = strcmp(name, entp->name)) > 0)
173 if (entp == NULL || c != 0) { /* Not found; create a new entry. */
174 newp = NEW(hashent, 1);
175 newp->name = xstrdup(name);
186 * Return a hash value for the given string.
194 while((ch = *s) != '\0') {
202 * Enter the linker sets from the given ELF object file. Returns 0 on
203 * success, or -1 if an error occurred.
206 enter_sets(const char *filename)
214 if ((iop = fopen(filename, "rb")) == NULL) {
215 warn("%s", filename);
218 if (fread(&ehdr, sizeof ehdr, 1, iop) != 1 ||
219 ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
220 ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
221 ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
222 ehdr.e_ident[EI_MAG3] != ELFMAG3) {
223 warnx("%s: not an ELF file", filename);
227 if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
228 warnx("%s: unsupported ELF version", filename);
232 if (ehdr.e_ident[EI_DATA] != my_byte_order()) {
233 warnx("%s: unsupported byte order", filename);
237 if (ehdr.e_shoff == 0) {
238 warnx("%s: no section table", filename);
242 if (ehdr.e_shstrndx == SHN_UNDEF) {
243 warnx("%s: no section name string table", filename);
248 shdr = NEW(Elf_Shdr, ehdr.e_shnum);
249 if (fseek(iop, ehdr.e_shoff, SEEK_SET) == -1) {
250 warn("%s", filename);
255 if (fread(shdr, sizeof *shdr, ehdr.e_shnum, iop) != ehdr.e_shnum) {
256 warnx("%s: truncated section table", filename);
262 shstr = NEW(char, shdr[ehdr.e_shstrndx].sh_size);
263 if (fseek(iop, shdr[ehdr.e_shstrndx].sh_offset, SEEK_SET) == -1) {
264 warn("%s", filename);
270 if (fread(shstr, sizeof *shstr, shdr[ehdr.e_shstrndx].sh_size, iop) !=
271 shdr[ehdr.e_shstrndx].sh_size) {
272 warnx("%s: truncated section name string table", filename);
279 for (i = 1; i < ehdr.e_shnum; i++) {
280 const char *name = shstr + shdr[i].sh_name;
282 if (strncmp(name, PREFIX, sizeof (PREFIX) - 1) == 0)
283 enter(name + sizeof (PREFIX) - 1, shdr[i].sh_size);
293 * Destructively merge all the sorted hash chains into a single sorted
294 * list, and return a pointer to its first element.
299 unsigned int numchains = HASHSIZE;
301 while (numchains > 1) { /* More merging to do. */
304 * Merge chains pairwise from the outside in, halving the
307 while (numchains - lo >= 2) {
308 hashent **linkp = &hashtab[lo];
309 hashent *l1 = hashtab[lo++];
310 hashent *l2 = hashtab[--numchains];
312 while (l1 != NULL && l2 != NULL) {
313 if (strcmp(l1->name, l2->name) < 0) {
323 *linkp = l1==NULL ? l2 : l1;
331 * Determine the host byte order.
336 static unsigned short s = 0xbbaa;
339 byte0 = *(unsigned char *)&s;
341 return (ELFDATA2LSB);
342 else if (byte0 == 0xbb)
343 return (ELFDATA2MSB);
345 return (ELFDATANONE);
349 * Allocate a chunk of memory and return a pointer to it. Die if the
359 err(EXIT_FAILURE, "malloc");
364 * Duplicate a string and return a pointer to the copy. Die if there is
368 xstrdup(const char *s)
372 size = strlen(s) + 1;
373 return (memcpy(xmalloc(size), s, size));