Cut our umbilical cord from mother FreeBSD.
[dragonfly.git] / usr.bin / gensetdefs / gensetdefs.c
1 /*-
2  * Copyright (c) 1997 John D. Polstra.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
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.3 2003/09/17 02:07:42 drhodus Exp $
28  */
29
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>
37 #endif
38 #include <sys/elf_generic.h>
39
40 #include <err.h>
41 #include <stddef.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #define HASHSIZE        1009u   /* Number of hash chains. */
47 #define PREFIX          ".set." /* Section name prefix for linker sets. */
48
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. */
54 } hashent;
55
56 /* Allocate storage for "count" objects of type "type". */
57 #define NEW(type, count)        ((type *) xmalloc((count) * sizeof(type)))
58
59 static hashent *hashtab[HASHSIZE];      /* Hash chain heads. */
60
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 *);
68
69 /*
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.
76  */
77 int
78 main(int argc, char **argv)
79 {
80         int      i;
81         int      status = EXIT_SUCCESS;
82         hashent *list;
83         FILE    *fp;
84         char    *ptrop;
85         int      align;
86
87         for (i = 1;  i < argc;  i++)
88                 if (enter_sets(argv[i]) == -1)
89                         status = EXIT_FAILURE;
90
91         fp = fopen("setdefs.h", "w");
92         if (!fp)
93                 err(1, "setdefs.h");
94         list = merge();
95         while (list != NULL) {
96                 hashent *next;
97
98                 fprintf(fp, "DEFINE_SET(%s, %lu);\n", list->name,
99                         (unsigned long) (list->size / sizeof (void *)));
100                 next = list->next;
101                 free(list->name);
102                 free(list);
103                 list = next;
104         }
105         fclose(fp);
106
107 #if defined(arch_i386)
108         ptrop = "long";
109         align = 2;
110 #elif defined(arch_alpha)
111         ptrop = "quad";
112         align = 3;
113 #endif
114         if (!ptrop)
115                 errx(1, "unknown architecture");
116
117         fp = fopen("setdef0.c", "w");
118         if (!fp)
119                 err(1, "setdef0.c");
120
121         fprintf(fp, "/* THIS FILE IS GENERATED, DO NOT EDIT. */\n\n");
122         fprintf(fp, "\
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\
131 \n\
132 #include \"setdefs.h\"          /* Contains a `DEFINE_SET' for each set */\n\
133 ", align, ptrop);
134
135         fclose(fp);
136
137         fp = fopen("setdef1.c", "w");
138         if (!fp)
139                 err(1, "setdef0.c");
140
141         fprintf(fp, "/* THIS FILE IS GENERATED, DO NOT EDIT. */\n\n");
142         fprintf(fp, "\
143 #define DEFINE_SET(set, count)                          \\\n\
144 __asm__(\".section .set.\" #set \",\\\"aw\\\"\");       \\\n\
145 __asm__(\".%s 0\");                     \\\n\
146 __asm__(\".previous\")\n\
147 \n\
148 #include \"setdefs.h\"          /* Contains a `DEFINE_SET' for each set */\n\
149 ", ptrop);
150
151         fclose(fp);
152
153         return (status);
154 }
155
156 /*
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.
160  */
161 static void
162 enter(const char *name, size_t size)
163 {
164         int       c = 0;
165         hashent  *entp;
166         hashent **linkp;
167         hashent  *newp;
168
169         linkp = &hashtab[hash(name) % HASHSIZE];
170         while ((entp = *linkp) != NULL && (c = strcmp(name, entp->name)) > 0)
171                 linkp = &entp->next;
172
173         if (entp == NULL || c != 0) {   /* Not found; create a new entry. */
174                 newp = NEW(hashent, 1);
175                 newp->name = xstrdup(name);
176                 newp->size = 0;
177                 newp->next = entp;
178                 *linkp = newp;
179                 entp = newp;
180         }
181
182         entp->size += size;
183 }
184
185 /*
186  * Return a hash value for the given string.
187  */
188 static unsigned int
189 hash(const char *s)
190 {
191         unsigned char   ch;
192         unsigned int    h = 0;
193
194         while((ch = *s) != '\0') {
195                 h = 9*h +  ch;
196                 s++;
197         }
198         return (h);
199 }
200
201 /*
202  * Enter the linker sets from the given ELF object file.  Returns 0 on
203  * success, or -1 if an error occurred.
204  */
205 static int
206 enter_sets(const char *filename)
207 {
208         int              i;
209         FILE            *iop;
210         Elf_Shdr        *shdr;
211         char            *shstr;
212         Elf_Ehdr         ehdr;
213
214         if ((iop = fopen(filename, "rb")) == NULL) {
215                 warn("%s", filename);
216                 return (-1);
217         }
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);
224                 fclose(iop);
225                 return (-1);
226         }
227         if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
228                 warnx("%s: unsupported ELF version", filename);
229                 fclose(iop);
230                 return (-1);
231         }
232         if (ehdr.e_ident[EI_DATA] != my_byte_order()) {
233                 warnx("%s: unsupported byte order", filename);
234                 fclose(iop);
235                 return (-1);
236         }
237         if (ehdr.e_shoff == 0) {
238                 warnx("%s: no section table", filename);
239                 fclose(iop);
240                 return (-1);
241         }
242         if (ehdr.e_shstrndx == SHN_UNDEF) {
243                 warnx("%s: no section name string table", filename);
244                 fclose(iop);
245                 return (-1);
246         }
247
248         shdr = NEW(Elf_Shdr, ehdr.e_shnum);
249         if (fseek(iop, ehdr.e_shoff, SEEK_SET) == -1) {
250                 warn("%s", filename);
251                 free(shdr);
252                 fclose(iop);
253                 return (-1);
254         }
255         if (fread(shdr, sizeof *shdr, ehdr.e_shnum, iop) != ehdr.e_shnum) {
256                 warnx("%s: truncated section table", filename);
257                 free(shdr);
258                 fclose(iop);
259                 return (-1);
260         }
261
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);
265                 free(shstr);
266                 free(shdr);
267                 fclose(iop);
268                 return (-1);
269         }
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);
273                 free(shstr);
274                 free(shdr);
275                 fclose(iop);
276                 return (-1);
277         }
278
279         for (i = 1;  i < ehdr.e_shnum;  i++) {
280                 const char *name = shstr + shdr[i].sh_name;
281
282                 if (strncmp(name, PREFIX, sizeof (PREFIX) - 1) == 0)
283                         enter(name + sizeof (PREFIX) - 1, shdr[i].sh_size);
284         }
285
286         free(shstr);
287         free(shdr);
288         fclose(iop);
289         return (0);
290 }
291
292 /*
293  * Destructively merge all the sorted hash chains into a single sorted
294  * list, and return a pointer to its first element.
295  */
296 static hashent *
297 merge(void)
298 {
299         unsigned int numchains = HASHSIZE;
300
301         while (numchains > 1) {         /* More merging to do. */
302                 unsigned int lo = 0;
303                 /*
304                  * Merge chains pairwise from the outside in, halving the
305                  * number of chains.
306                  */
307                 while (numchains - lo >= 2) {
308                         hashent **linkp = &hashtab[lo];
309                         hashent  *l1 = hashtab[lo++];
310                         hashent  *l2 = hashtab[--numchains];
311
312                         while (l1 != NULL && l2 != NULL) {
313                                 if (strcmp(l1->name, l2->name) < 0) {
314                                         *linkp = l1;
315                                         linkp = &l1->next;
316                                         l1 = l1->next;
317                                 } else {
318                                         *linkp = l2;
319                                         linkp = &l2->next;
320                                         l2 = l2->next;
321                                 }
322                         }
323                         *linkp = l1==NULL ? l2 : l1;
324                 }
325         }
326
327         return (hashtab[0]);
328 }
329
330 /*
331  * Determine the host byte order.
332  */
333 static int
334 my_byte_order(void)
335 {
336         static unsigned short   s = 0xbbaa;
337         int                     byte0;
338
339         byte0 = *(unsigned char *)&s;
340         if (byte0 == 0xaa)
341                 return (ELFDATA2LSB);
342         else if (byte0 == 0xbb)
343                 return (ELFDATA2MSB);
344         else
345                 return (ELFDATANONE);
346 }
347
348 /*
349  * Allocate a chunk of memory and return a pointer to it.  Die if the
350  * malloc fails.
351  */
352 static void *
353 xmalloc(size_t size)
354 {
355         void *p;
356
357         p = malloc(size);
358         if (p == NULL)
359                 err(EXIT_FAILURE, "malloc");
360         return (p);
361 }
362
363 /*
364  * Duplicate a string and return a pointer to the copy.  Die if there is
365  * not enough memory.
366  */
367 static char *
368 xstrdup(const char *s)
369 {
370         int size;
371
372         size = strlen(s) + 1;
373         return (memcpy(xmalloc(size), s, size));
374 }