]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/alpha/alpha/gensetdefs.c
This commit was generated by cvs2svn to compensate for changes in r58653,
[FreeBSD/FreeBSD.git] / sys / alpha / alpha / 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$
27  */
28
29 #include <sys/types.h>
30 #include "../../alpha/include/elf.h"
31
32 #include <err.h>
33 #include <stddef.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #define HASHSIZE        1009u   /* Number of hash chains. */
39 #define PREFIX          ".set." /* Section name prefix for linker sets. */
40
41 /* One entry in the hash table. */
42 typedef struct hashent {
43         struct hashent *next;   /* Next entry with the same hash. */
44         char *name;             /* Name of the linker set. */
45         size_t size;            /* Size in bytes. */
46 } hashent;
47
48 /* Allocate storage for "count" objects of type "type". */
49 #define NEW(type, count)        ((type *) xmalloc((count) * sizeof(type)))
50
51 static hashent *hashtab[HASHSIZE];      /* Hash chain heads. */
52
53 static void              enter(const char *, size_t);
54 static int               enter_sets(const char *);
55 static unsigned int      hash(const char *);
56 static hashent          *merge(void);
57 static int               my_byte_order(void);
58 static void             *xmalloc(size_t);
59 static char             *xstrdup(const char *);
60
61 /*
62  * This is a special-purpose program to generate the linker set definitions
63  * needed when building an ELF kernel.  Its arguments are the names of
64  * ELF object files.  It scans the section names of the object files,
65  * building a table of those that begin with ".set.", which represent
66  * linker sets.  Finally, for each set "foo" with "count" elements, it
67  * writes a line "DEFINE_SET(foo, count);" to the standard output.
68  */
69 int
70 main(int argc, char **argv)
71 {
72         int      i;
73         int      status = EXIT_SUCCESS;
74         hashent *list;
75
76         for (i = 1;  i < argc;  i++)
77                 if (enter_sets(argv[i]) == -1)
78                         status = EXIT_FAILURE;
79
80         list = merge();
81         while (list != NULL) {
82                 hashent *next;
83
84                 printf("DEFINE_SET(%s, %lu);\n", list->name,
85                     (unsigned long) (list->size / sizeof (void *)));
86                 next = list->next;
87                 free(list->name);
88                 free(list);
89                 list = next;
90         }
91
92         return (status);
93 }
94
95 /*
96  * Enter the given string into the hash table, if it is not already there.
97  * Each hash chain is kept sorted, so that it will be easy to merge the
98  * chains to get a single sorted list.
99  */
100 static void
101 enter(const char *name, size_t size)
102 {
103         int       c = 0;
104         hashent  *entp;
105         hashent **linkp;
106         hashent  *newp;
107
108         linkp = &hashtab[hash(name) % HASHSIZE];
109         while ((entp = *linkp) != NULL && (c = strcmp(name, entp->name)) > 0)
110                 linkp = &entp->next;
111
112         if (entp == NULL || c != 0) {   /* Not found; create a new entry. */
113                 newp = NEW(hashent, 1);
114                 newp->name = xstrdup(name);
115                 newp->size = 0;
116                 newp->next = entp;
117                 *linkp = newp;
118                 entp = newp;
119         }
120
121         entp->size += size;
122 }
123
124 /*
125  * Return a hash value for the given string.
126  */
127 static unsigned int
128 hash(const char *s)
129 {
130         unsigned char   ch;
131         unsigned int    h = 0;
132
133         while((ch = *s) != '\0') {
134                 h = 9*h +  ch;
135                 s++;
136         }
137         return (h);
138 }
139
140 /*
141  * Enter the linker sets from the given ELF object file.  Returns 0 on
142  * success, or -1 if an error occurred.
143  */
144 static int
145 enter_sets(const char *filename)
146 {
147         int              i;
148         FILE            *iop;
149         Elf64_Shdr      *shdr;
150         char            *shstr;
151         Elf64_Ehdr       ehdr;
152
153         if ((iop = fopen(filename, "rb")) == NULL) {
154                 warn("%s", filename);
155                 return (-1);
156         }
157         if (fread(&ehdr, sizeof ehdr, 1, iop) != 1 ||
158             ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
159             ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
160             ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
161             ehdr.e_ident[EI_MAG3] != ELFMAG3) {
162                 warnx("%s: not an ELF file", filename);
163                 fclose(iop);
164                 return (-1);
165         }
166         if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
167                 warnx("%s: unsupported ELF version", filename);
168                 fclose(iop);
169                 return (-1);
170         }
171         if (ehdr.e_ident[EI_DATA] != my_byte_order()) {
172                 warnx("%s: unsupported byte order", filename);
173                 fclose(iop);
174                 return (-1);
175         }
176         if (ehdr.e_shoff == 0) {
177                 warnx("%s: no section table", filename);
178                 fclose(iop);
179                 return (-1);
180         }
181         if (ehdr.e_shstrndx == SHN_UNDEF) {
182                 warnx("%s: no section name string table", filename);
183                 fclose(iop);
184                 return (-1);
185         }
186
187         shdr = NEW(Elf64_Shdr, ehdr.e_shnum);
188         if (fseek(iop, ehdr.e_shoff, SEEK_SET) == -1) {
189                 warn("%s", filename);
190                 free(shdr);
191                 fclose(iop);
192                 return (-1);
193         }
194         if (fread(shdr, sizeof *shdr, ehdr.e_shnum, iop) != ehdr.e_shnum) {
195                 warnx("%s: truncated section table", filename);
196                 free(shdr);
197                 fclose(iop);
198                 return (-1);
199         }
200
201         shstr = NEW(char, shdr[ehdr.e_shstrndx].sh_size);
202         if (fseek(iop, shdr[ehdr.e_shstrndx].sh_offset, SEEK_SET) == -1) {
203                 warn("%s", filename);
204                 free(shstr);
205                 free(shdr);
206                 fclose(iop);
207                 return (-1);
208         }
209         if (fread(shstr, sizeof *shstr, shdr[ehdr.e_shstrndx].sh_size, iop) !=
210             shdr[ehdr.e_shstrndx].sh_size) {
211                 warnx("%s: truncated section name string table", filename);
212                 free(shstr);
213                 free(shdr);
214                 fclose(iop);
215                 return (-1);
216         }
217
218         for (i = 1;  i < ehdr.e_shnum;  i++) {
219                 const char *name = shstr + shdr[i].sh_name;
220
221                 if (strncmp(name, PREFIX, sizeof (PREFIX) - 1) == 0)
222                         enter(name + sizeof (PREFIX) - 1, shdr[i].sh_size);
223         }
224
225         free(shstr);
226         free(shdr);
227         fclose(iop);
228         return (0);
229 }
230
231 /*
232  * Destructively merge all the sorted hash chains into a single sorted
233  * list, and return a pointer to its first element.
234  */
235 static hashent *
236 merge(void)
237 {
238         unsigned int numchains = HASHSIZE;
239
240         while (numchains > 1) {         /* More merging to do. */
241                 unsigned int lo = 0;
242                 /*
243                  * Merge chains pairwise from the outside in, halving the
244                  * number of chains.
245                  */
246                 while (numchains - lo >= 2) {
247                         hashent **linkp = &hashtab[lo];
248                         hashent  *l1 = hashtab[lo++];
249                         hashent  *l2 = hashtab[--numchains];
250
251                         while (l1 != NULL && l2 != NULL) {
252                                 if (strcmp(l1->name, l2->name) < 0) {
253                                         *linkp = l1;
254                                         linkp = &l1->next;
255                                         l1 = l1->next;
256                                 } else {
257                                         *linkp = l2;
258                                         linkp = &l2->next;
259                                         l2 = l2->next;
260                                 }
261                         }
262                         *linkp = l1==NULL ? l2 : l1;
263                 }
264         }
265
266         return (hashtab[0]);
267 }
268
269 /*
270  * Determine the host byte order.
271  */
272 static int
273 my_byte_order(void)
274 {
275         static unsigned short   s = 0xbbaa;
276         int                     byte0;
277
278         byte0 = *(unsigned char *)&s;
279         if (byte0 == 0xaa)
280                 return (ELFDATA2LSB);
281         else if (byte0 == 0xbb)
282                 return (ELFDATA2MSB);
283         else
284                 return (ELFDATANONE);
285 }
286
287 /*
288  * Allocate a chunk of memory and return a pointer to it.  Die if the
289  * malloc fails.
290  */
291 static void *
292 xmalloc(size_t size)
293 {
294         void *p;
295
296         p = malloc(size);
297         if (p == NULL)
298                 err(EXIT_FAILURE, "malloc");
299         return (p);
300 }
301
302 /*
303  * Duplicate a string and return a pointer to the copy.  Die if there is
304  * not enough memory.
305  */
306 static char *
307 xstrdup(const char *s)
308 {
309         int size;
310
311         size = strlen(s) + 1;
312         return (memcpy(xmalloc(size), s, size));
313 }