Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.bin / genassym / genassym.c
1 /*-
2  * Copyright (c) 1999 Marcel Moolenaar
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  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/usr.bin/genassym/genassym.c,v 1.1 1999/12/23 11:07:45 marcel Exp $
29  */
30
31 #include <sys/types.h>
32 #if defined(arch_i386)
33 #include <sys/elf32.h>
34 #define __ELF_WORD_SIZE 32
35 #elif defined(arch_alpha)
36 #include <sys/elf64.h>
37 #define __ELF_WORD_SIZE 64
38 #else
39 #error unknown or missing architecture
40 #endif
41 #include <sys/elf_generic.h>
42
43 #include <err.h>
44 #include <fcntl.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <unistd.h>
49
50 const char s_data[] = ".data";
51 const char s_strtab[] = ".strtab";
52 const char s_symtab[] = ".symtab";
53 const char assym[] = "assym_";
54
55 int fd;
56 char *objfile;
57 Elf_Ehdr ehdr;
58 Elf_Shdr *shdr;
59 char *shstr;
60
61 int
62 my_byte_order(void)
63 {
64         static unsigned short s = 0xbbaa;
65         int byte0;
66
67         byte0 = *(unsigned char *)&s;
68         if (byte0 == 0xaa)
69                 return (ELFDATA2LSB);
70         else if (byte0 == 0xbb)
71                 return (ELFDATA2MSB);
72         return (ELFDATANONE);
73 }
74
75 void *
76 read_section(int index)
77 {
78         void *buf;
79         size_t size;
80         ssize_t bytes;
81
82         size = shdr[index].sh_size;
83         buf = malloc(size);
84         if (buf == NULL)
85                 return (NULL);
86         if (lseek(fd, shdr[index].sh_offset, SEEK_SET) == -1)
87                 return (NULL);
88         bytes = read(fd, buf, size);
89         if (bytes == -1)
90                 return (NULL);
91         if (bytes != size)
92                 warnx("%s: section %d partially read", objfile, index);
93         return (buf);
94 }
95
96 int section_index(const char *section)
97 {
98         int i;
99
100         for (i = 1; i < ehdr.e_shnum; i++)
101                 if (!strcmp(section, shstr + shdr[i].sh_name))
102                         return (i);
103         return (-1);
104 }
105
106 char *
107 filter(char *name)
108 {
109         char *dot;
110
111         name += sizeof(assym) - 1;
112         dot = strchr(name, '.');
113         if (dot != NULL)
114                 *dot = '\0';
115         return (name);
116 }
117
118 void usage(void)
119 {
120         fprintf(stderr, "usage: genassym [-o outfile] objfile\n");
121         exit(1);
122         /* NOT REACHED */
123 }
124
125 int
126 main(int argc, char *argv[])
127 {
128         Elf_Sym *sym;
129         char *data, *name, *symbols;
130         char *outfile;
131         void *valp;
132         size_t size;
133         ssize_t bytes;
134         int ch, i, numsym, warn_ld_bug;
135         int si_data, si_strtab, si_symtab;
136         u_int64_t value;
137
138         outfile = NULL;
139         warn_ld_bug = 1;
140
141         while ((ch = getopt(argc, argv, "o:")) != -1) {
142                 switch (ch) {
143                 case 'o':
144                         outfile = optarg;
145                         break;
146                 default:
147                         usage();
148                         /* NOT REACHED */
149                 }
150         }
151         argc -= optind;
152         argv += optind;
153
154         if (argc == 0) {
155                 usage();
156                 /* NOT REACHED */
157         }
158         if (argc > 1)
159                 warnx("ignoring trailing arguments");
160
161         objfile = argv[0];
162         fd = open(objfile, O_RDONLY);
163         if (fd == -1)
164                 err(1, "%s", objfile);
165
166         bytes = read(fd, &ehdr, sizeof(ehdr));
167         if (bytes == -1)
168                 err(1, "%s", objfile);
169         if (bytes != sizeof(ehdr) ||
170             ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
171             ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
172             ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
173             ehdr.e_ident[EI_MAG3] != ELFMAG3)
174                 errx(1, "%s: not an ELF file", objfile);
175         if (ehdr.e_ident[EI_VERSION] != EV_CURRENT)
176                 errx(1, "%s: unsupported ELF version", objfile);
177         if (ehdr.e_ident[EI_DATA] != my_byte_order())
178                 errx(1, "%s: unsupported byte order", objfile);
179         if (ehdr.e_shoff == 0)
180                 errx(1, "%s: no section table", objfile);
181         if (ehdr.e_shstrndx == SHN_UNDEF)
182                 errx(1, "%s: no section name string table", objfile);
183
184         size = sizeof(*shdr) * ehdr.e_shnum;
185         shdr = malloc(size);
186         if (shdr == NULL)
187                 err(1, "malloc");
188         if (lseek(fd, ehdr.e_shoff, SEEK_SET) == -1)
189                 err(1, "%s", objfile);
190         bytes = read(fd, shdr, size);
191         if (bytes == -1)
192                 err(1, "%s", objfile);
193         if (bytes != size)
194                 errx(1, "%s: truncated section table", objfile);
195
196         shstr = read_section(ehdr.e_shstrndx);
197         if (shstr == NULL)
198                 err(1, "%s[%d]", objfile, ehdr.e_shstrndx);
199
200         si_data = section_index(s_data);
201         if (si_data == -1)
202                 errx(1, "%s: section %s not present", objfile, s_data);
203         data = read_section(si_data);
204         if (data == NULL)
205                 err(1, "%s[%d]", objfile, si_data);
206
207         si_strtab = section_index(s_strtab);
208         if (si_strtab == -1)
209                 errx(1, "%s: section %s not present", objfile, s_strtab);
210         symbols = read_section(si_strtab);
211         if (symbols == NULL)
212                 err(1, "%s[%d]", objfile, si_strtab);
213
214         si_symtab = section_index(s_symtab);
215         if (si_symtab == -1)
216                 errx(1, "%s: section %s not present", objfile, s_symtab);
217         sym = read_section(si_symtab);
218         if (sym == NULL)
219                 err(1, "%s[%d]", objfile, si_symtab);
220
221         numsym = shdr[si_symtab].sh_size / sizeof(*sym);
222
223         if (outfile != NULL)
224                 freopen(outfile, "w", stdout);
225
226         for (i = 0; i < numsym; i++) {
227                 name = symbols + sym[i].st_name;
228                 if (sym[i].st_shndx == si_data &&
229                     !strncmp(name, assym, sizeof(assym) - 1)) {
230                         valp = (void*)(data + sym[i].st_value);
231                         /*
232                          * XXX - ld(1) on Alpha doesn't store the size of
233                          * the symbol in the object file. The following
234                          * fix handles this case quite genericly. It
235                          * assumes that the symbols have the same size as
236                          * a word on that architecture, determined by the
237                          * word size in the ELF object file.
238                          */
239                         if (sym[i].st_size == 0) {
240                                 sym[i].st_size = __ELF_WORD_SIZE >> 3;
241                                 if (warn_ld_bug) {
242                                         warnx("%s: symbol sizes not properly"
243                                             " set", objfile);
244                                         warn_ld_bug = 0;
245                                 }
246                         }
247                         switch (sym[i].st_size) {
248                         case 1:
249                                 value = *(u_int8_t*)valp;
250                                 break;
251                         case 2:
252                                 value = *(u_int16_t*)valp;
253                                 break;
254                         case 4:
255                                 value = *(u_int32_t*)valp;
256                                 break;
257                         case 8:
258                                 value = *(u_int64_t*)valp;
259                                 break;
260                         default:
261                                 warnx("unsupported size (%lld) for symbol %s",
262                                     (long long)sym[i].st_size, filter(name));
263                                 continue;
264                         }
265                         fprintf(stdout, "#define\t%s 0x%llx\n", filter(name),
266                             (long long)value);
267                 }
268         }
269
270         return (0);
271 }