elf.c revision 1.6 1 1.6 wiz /* $NetBSD: elf.c,v 1.6 2002/12/22 13:50:36 wiz Exp $ */
2 1.4 takemura
3 1.4 takemura /*-
4 1.4 takemura * Copyright (c) 1999 Shin Takemura.
5 1.4 takemura * All rights reserved.
6 1.4 takemura *
7 1.4 takemura * This software is part of the PocketBSD.
8 1.4 takemura *
9 1.4 takemura * Redistribution and use in source and binary forms, with or without
10 1.4 takemura * modification, are permitted provided that the following conditions
11 1.4 takemura * are met:
12 1.4 takemura * 1. Redistributions of source code must retain the above copyright
13 1.4 takemura * notice, this list of conditions and the following disclaimer.
14 1.4 takemura * 2. Redistributions in binary form must reproduce the above copyright
15 1.4 takemura * notice, this list of conditions and the following disclaimer in the
16 1.4 takemura * documentation and/or other materials provided with the distribution.
17 1.4 takemura * 3. All advertising materials mentioning features or use of this software
18 1.4 takemura * must display the following acknowledgement:
19 1.4 takemura * This product includes software developed by the PocketBSD project
20 1.4 takemura * and its contributors.
21 1.4 takemura * 4. Neither the name of the project nor the names of its contributors
22 1.4 takemura * may be used to endorse or promote products derived from this software
23 1.4 takemura * without specific prior written permission.
24 1.4 takemura *
25 1.4 takemura * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 1.4 takemura * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 1.4 takemura * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 1.4 takemura * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 1.4 takemura * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 1.4 takemura * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 1.4 takemura * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 1.4 takemura * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 1.4 takemura * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 1.4 takemura * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 1.4 takemura * SUCH DAMAGE.
36 1.4 takemura *
37 1.4 takemura */
38 1.4 takemura #include <pbsdboot.h>
39 1.4 takemura
40 1.4 takemura #define ELFSIZE 32
41 1.4 takemura //#include <sys/param.h>
42 1.4 takemura //#include <sys/exec.h>
43 1.4 takemura #include <sys/exec_elf.h>
44 1.4 takemura
45 1.4 takemura #if 1
46 1.4 takemura #define LOAD_DEBUG_INFO
47 1.4 takemura #define DEBUG_INFO_ALIGN 4096
48 1.4 takemura #define ROUNDUP(a, n) ((((int)(a)) + (n)-1)/(n)*(n))
49 1.4 takemura #endif
50 1.4 takemura
51 1.4 takemura static int
52 1.4 takemura scanfile(int fd, caddr_t *start, caddr_t *end, caddr_t *entry, int load);
53 1.4 takemura
54 1.4 takemura static long total_bytes = 0;
55 1.4 takemura
56 1.4 takemura int
57 1.4 takemura getinfo(int fd, caddr_t *start, caddr_t *end)
58 1.4 takemura {
59 1.4 takemura return (scanfile(fd, start, end, NULL, 0));
60 1.4 takemura }
61 1.4 takemura
62 1.4 takemura int
63 1.4 takemura loadfile(int fd, caddr_t *entry)
64 1.4 takemura {
65 1.4 takemura return (scanfile(fd, NULL, NULL, entry, 1));
66 1.4 takemura }
67 1.4 takemura
68 1.4 takemura enum {
69 1.4 takemura VMEM_CLEAR, VMEM_LOAD, VMEM_COPY
70 1.4 takemura };
71 1.4 takemura
72 1.4 takemura int
73 1.4 takemura vmem_sub(int opr, void* xxx, caddr_t addr, int nbytes, int *byte_count)
74 1.4 takemura {
75 1.4 takemura int n;
76 1.4 takemura caddr_t end_addr, vaddr;
77 1.4 takemura int count = 0;
78 1.4 takemura int progress = 0;
79 1.4 takemura int fd = (int)xxx;
80 1.4 takemura caddr_t src_addr = (caddr_t)xxx;
81 1.4 takemura
82 1.4 takemura debug_printf(TEXT("loadfile_sub(%x-%x, %S)\n"),
83 1.4 takemura addr, addr + nbytes,
84 1.4 takemura opr == VMEM_CLEAR ? "clear" : (opr == VMEM_LOAD ? "load" : "copy"));
85 1.4 takemura
86 1.4 takemura for (end_addr = addr + nbytes;
87 1.4 takemura addr < end_addr;
88 1.4 takemura addr += n) {
89 1.4 takemura if ((vaddr = vmem_get(addr, &n)) == NULL) {
90 1.4 takemura debug_printf(TEXT("vmem_get(0x%x) failed.\n"), addr);
91 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("vmem_get(0x%x) failed.\n"), addr);
92 1.4 takemura return (-1);
93 1.4 takemura }
94 1.4 takemura if (end_addr < addr + n) {
95 1.4 takemura n = end_addr - addr;
96 1.4 takemura }
97 1.4 takemura switch (opr) {
98 1.4 takemura case VMEM_CLEAR:
99 1.4 takemura memset(vaddr, 0, n);
100 1.4 takemura break;
101 1.4 takemura case VMEM_LOAD:
102 1.4 takemura if (read(fd, vaddr, n) != n) {
103 1.4 takemura debug_printf(TEXT("read segment error.\n"));
104 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("read segment error.\n"));
105 1.4 takemura return (-1);
106 1.4 takemura }
107 1.4 takemura break;
108 1.4 takemura case VMEM_COPY:
109 1.4 takemura memcpy(vaddr, src_addr, n);
110 1.4 takemura src_addr += n;
111 1.4 takemura break;
112 1.4 takemura }
113 1.4 takemura if (total_bytes != 0) {
114 1.4 takemura int tmp_progress = *byte_count * 100 / total_bytes;
115 1.4 takemura *byte_count += n;
116 1.4 takemura if (progress != tmp_progress) {
117 1.4 takemura progress = tmp_progress;
118 1.4 takemura if (CheckCancel(progress)) {
119 1.4 takemura return (-1);
120 1.4 takemura }
121 1.4 takemura }
122 1.4 takemura }
123 1.4 takemura }
124 1.4 takemura return (0);
125 1.4 takemura }
126 1.4 takemura
127 1.4 takemura
128 1.4 takemura static int
129 1.4 takemura scanfile(int fd, caddr_t *start, caddr_t *end, caddr_t *entry, int load)
130 1.4 takemura {
131 1.4 takemura Elf_Ehdr elfx, *elf = &elfx;
132 1.4 takemura int i, first;
133 1.4 takemura long byte_count;
134 1.4 takemura int progress;
135 1.4 takemura Elf_Shdr *shtbl = NULL;
136 1.4 takemura Elf_Phdr *phtbl = NULL;
137 1.4 takemura caddr_t min_addr, max_addr;
138 1.4 takemura int sh_symidx, sh_stridx;
139 1.4 takemura int dbg_hdr_size = sizeof(Elf_Ehdr) + sizeof(Elf_Shdr) * 2;
140 1.4 takemura
141 1.4 takemura if (lseek(fd, 0, SEEK_SET) == -1) {
142 1.4 takemura debug_printf(TEXT("seek error\n"));
143 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("seek error.\n"));
144 1.4 takemura goto error_cleanup;
145 1.4 takemura }
146 1.4 takemura if (read(fd, (void*)elf, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr)) {
147 1.4 takemura debug_printf(TEXT("read header error\n"));
148 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("read header error.\n"));
149 1.4 takemura goto error_cleanup;
150 1.4 takemura }
151 1.4 takemura
152 1.4 takemura if ((phtbl = (Elf_Phdr *)alloc(sizeof(*phtbl) * elf->e_phnum)) == NULL ||
153 1.4 takemura (shtbl = (Elf_Shdr *)alloc(sizeof(*shtbl) * elf->e_shnum)) == NULL) {
154 1.4 takemura debug_printf(TEXT("alloc() error\n"));
155 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("malloc() error.\n"));
156 1.4 takemura goto error_cleanup;
157 1.4 takemura }
158 1.4 takemura
159 1.4 takemura if (lseek(fd, elf->e_phoff, SEEK_SET) == -1) {
160 1.4 takemura debug_printf(TEXT("seek for program header table error\n"));
161 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("seek for program header table error.\n"));
162 1.4 takemura goto error_cleanup;
163 1.4 takemura }
164 1.4 takemura if (read(fd, (void *)phtbl, sizeof(Elf_Phdr) * elf->e_phnum)
165 1.4 takemura != (int)(sizeof(Elf_Phdr) * elf->e_phnum)) {
166 1.4 takemura debug_printf(TEXT("read program header table error\n"));
167 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("read program header table error.\n"));
168 1.4 takemura goto error_cleanup;
169 1.4 takemura }
170 1.4 takemura
171 1.4 takemura if (lseek(fd, elf->e_shoff, SEEK_SET) == -1) {
172 1.4 takemura debug_printf(TEXT("seek for segment header table error.\n"));
173 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("seek for segment header table error.\n"));
174 1.4 takemura goto error_cleanup;
175 1.4 takemura }
176 1.4 takemura if (read(fd, (void *)shtbl, sizeof(Elf_Shdr) * elf->e_shnum)
177 1.4 takemura != (int)(sizeof(Elf_Shdr) * elf->e_shnum)) {
178 1.4 takemura debug_printf(TEXT("read segment header table error\n"));
179 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("read segment header table error.\n"));
180 1.4 takemura goto error_cleanup;
181 1.4 takemura }
182 1.4 takemura
183 1.4 takemura /*
184 1.4 takemura * scan program header table
185 1.4 takemura */
186 1.4 takemura first = 1;
187 1.4 takemura byte_count = 0;
188 1.4 takemura progress = 0;
189 1.4 takemura for (i = 0; i < elf->e_phnum; i++) {
190 1.4 takemura if (phtbl[i].p_type != PT_LOAD) {
191 1.4 takemura continue;
192 1.4 takemura }
193 1.4 takemura
194 1.4 takemura if (first || max_addr < (caddr_t)(phtbl[i].p_vaddr + phtbl[i].p_memsz)) {
195 1.4 takemura max_addr = (caddr_t)(phtbl[i].p_vaddr + phtbl[i].p_memsz);
196 1.4 takemura }
197 1.4 takemura if (first || (caddr_t)phtbl[i].p_vaddr < min_addr) {
198 1.4 takemura min_addr = (caddr_t)phtbl[i].p_vaddr;
199 1.4 takemura }
200 1.4 takemura
201 1.4 takemura if (load) {
202 1.4 takemura if (lseek(fd, phtbl[i].p_offset, SEEK_SET) == -1) {
203 1.4 takemura debug_printf(TEXT("seek for segment error\n"));
204 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("seek for segment error.\n"));
205 1.4 takemura goto error_cleanup;
206 1.4 takemura }
207 1.4 takemura
208 1.4 takemura if (vmem_sub(VMEM_LOAD, (void*)fd,
209 1.4 takemura (caddr_t)phtbl[i].p_vaddr,
210 1.4 takemura phtbl[i].p_filesz,
211 1.4 takemura &byte_count) != 0) {
212 1.4 takemura goto error_cleanup;
213 1.4 takemura }
214 1.4 takemura if (vmem_sub(VMEM_CLEAR, NULL,
215 1.4 takemura (caddr_t)phtbl[i].p_vaddr + phtbl[i].p_filesz,
216 1.4 takemura phtbl[i].p_memsz - phtbl[i].p_filesz,
217 1.4 takemura &byte_count) != 0) {
218 1.4 takemura goto error_cleanup;
219 1.4 takemura }
220 1.4 takemura } else {
221 1.4 takemura byte_count += phtbl[i].p_memsz;
222 1.4 takemura }
223 1.4 takemura
224 1.4 takemura first = 0;
225 1.4 takemura }
226 1.4 takemura
227 1.4 takemura if (first) {
228 1.4 takemura debug_printf(TEXT("can't find loadable segment\n"));
229 1.4 takemura msg_printf(MSG_ERROR, whoami, TEXT("can't find loadable segment\n"));
230 1.4 takemura goto error_cleanup;
231 1.4 takemura }
232 1.4 takemura total_bytes = byte_count;
233 1.4 takemura
234 1.4 takemura debug_printf(TEXT("entry=%x addr=%x-%x\n"),
235 1.4 takemura elf->e_entry, min_addr, max_addr);
236 1.4 takemura
237 1.4 takemura #ifdef LOAD_DEBUG_INFO
238 1.4 takemura if (pref.load_debug_info) {
239 1.4 takemura /*
240 1.4 takemura * scan section header table
241 1.6 wiz * to search for debugging information
242 1.4 takemura */
243 1.4 takemura sh_symidx = -1;
244 1.4 takemura sh_stridx = -1;
245 1.4 takemura for (i = 0; i < elf->e_shnum; i++) {
246 1.4 takemura if (shtbl[i].sh_type == SHT_SYMTAB) {
247 1.4 takemura sh_symidx = i;
248 1.4 takemura }
249 1.4 takemura if ((shtbl[i].sh_type == SHT_STRTAB)
250 1.4 takemura && (shtbl[i].sh_size >= 0x4000)) {
251 1.4 takemura sh_stridx = i;
252 1.4 takemura }
253 1.4 takemura }
254 1.4 takemura if (sh_symidx == -1 || sh_stridx == -1) {
255 1.6 wiz debug_printf(TEXT("debugging information not found\n"));
256 1.4 takemura } else
257 1.4 takemura if (load) {
258 1.4 takemura Elf_Ehdr dbg_eh;
259 1.4 takemura Elf_Shdr dbg_sh[2];
260 1.4 takemura memset(&dbg_eh, 0, sizeof(Elf_Ehdr));
261 1.4 takemura memset(dbg_sh, 0, sizeof(Elf_Shdr) * 2);
262 1.4 takemura
263 1.4 takemura memcpy(dbg_eh.e_ident, elf->e_ident,
264 1.4 takemura sizeof(elf->e_ident));
265 1.4 takemura dbg_eh.e_machine = elf->e_machine;
266 1.4 takemura dbg_eh.e_version = elf->e_version;
267 1.4 takemura dbg_eh.e_entry = 0;
268 1.4 takemura dbg_eh.e_phoff = 0;
269 1.4 takemura dbg_eh.e_shoff = sizeof(Elf_Ehdr);
270 1.4 takemura dbg_eh.e_flags = elf->e_flags;
271 1.4 takemura dbg_eh.e_ehsize = sizeof(Elf_Ehdr);
272 1.4 takemura dbg_eh.e_phentsize = 0;
273 1.4 takemura dbg_eh.e_phnum = 0;
274 1.4 takemura dbg_eh.e_shentsize = sizeof(Elf_Shdr);
275 1.4 takemura dbg_eh.e_shnum = 2;
276 1.4 takemura dbg_eh.e_shstrndx = 0; /* ??? */
277 1.4 takemura
278 1.4 takemura /*
279 1.4 takemura * XXX, pass debug info size in e_entry.
280 1.4 takemura */
281 1.4 takemura dbg_eh.e_entry = ROUNDUP(dbg_hdr_size +
282 1.4 takemura shtbl[sh_symidx].sh_size +
283 1.4 takemura shtbl[sh_stridx].sh_size,
284 1.4 takemura DEBUG_INFO_ALIGN);
285 1.4 takemura
286 1.4 takemura if (vmem_sub(VMEM_COPY, (void*)&dbg_eh,
287 1.4 takemura max_addr,
288 1.4 takemura sizeof(Elf_Ehdr),
289 1.4 takemura &byte_count) != 0) {
290 1.4 takemura goto error_cleanup;
291 1.4 takemura }
292 1.4 takemura
293 1.4 takemura dbg_sh[0].sh_type = shtbl[sh_symidx].sh_type;
294 1.4 takemura dbg_sh[0].sh_offset = dbg_hdr_size;
295 1.4 takemura dbg_sh[0].sh_size = shtbl[sh_symidx].sh_size;
296 1.4 takemura dbg_sh[0].sh_addralign = shtbl[sh_symidx].sh_addralign;
297 1.4 takemura dbg_sh[1].sh_type = shtbl[sh_stridx].sh_type;
298 1.4 takemura dbg_sh[1].sh_offset = dbg_hdr_size + shtbl[sh_symidx].sh_size;
299 1.4 takemura dbg_sh[1].sh_size = shtbl[sh_stridx].sh_size;
300 1.4 takemura dbg_sh[1].sh_addralign = shtbl[sh_stridx].sh_addralign;
301 1.4 takemura if (vmem_sub(VMEM_COPY, (void*)dbg_sh,
302 1.4 takemura max_addr + sizeof(Elf_Ehdr),
303 1.4 takemura sizeof(Elf_Shdr) * 2,
304 1.4 takemura &byte_count) != 0) {
305 1.4 takemura goto error_cleanup;
306 1.4 takemura }
307 1.4 takemura
308 1.4 takemura if (lseek(fd, shtbl[sh_symidx].sh_offset, SEEK_SET) == -1) {
309 1.4 takemura debug_printf(TEXT("seek for debug symbol error\n"));
310 1.4 takemura msg_printf(MSG_ERROR, whoami,
311 1.4 takemura TEXT("seek for segment error.\n"));
312 1.4 takemura goto error_cleanup;
313 1.4 takemura }
314 1.4 takemura if (vmem_sub(VMEM_LOAD, (void*)fd,
315 1.4 takemura max_addr + dbg_hdr_size,
316 1.4 takemura shtbl[sh_symidx].sh_size,
317 1.4 takemura &byte_count) != 0) {
318 1.4 takemura goto error_cleanup;
319 1.4 takemura }
320 1.4 takemura
321 1.4 takemura if (lseek(fd, shtbl[sh_stridx].sh_offset, SEEK_SET) == -1) {
322 1.4 takemura debug_printf(TEXT("seek for string table error\n"));
323 1.4 takemura msg_printf(MSG_ERROR, whoami,
324 1.4 takemura TEXT("seek for segment error.\n"));
325 1.4 takemura goto error_cleanup;
326 1.4 takemura }
327 1.4 takemura if (vmem_sub(VMEM_LOAD, (void*)fd,
328 1.4 takemura max_addr + dbg_hdr_size + shtbl[sh_symidx].sh_size,
329 1.4 takemura shtbl[sh_stridx].sh_size,
330 1.4 takemura &byte_count) != 0) {
331 1.4 takemura goto error_cleanup;
332 1.4 takemura }
333 1.4 takemura } else {
334 1.4 takemura /*
335 1.6 wiz * make space for debugging information
336 1.4 takemura */
337 1.4 takemura int dbg_info_size = ROUNDUP(dbg_hdr_size +
338 1.4 takemura shtbl[sh_symidx].sh_size +
339 1.4 takemura shtbl[sh_stridx].sh_size,
340 1.4 takemura DEBUG_INFO_ALIGN);
341 1.5 toshii debug_printf(TEXT("%x bytes debug information\n"),
342 1.4 takemura dbg_info_size);
343 1.4 takemura max_addr += dbg_info_size;
344 1.4 takemura total_bytes += dbg_info_size;
345 1.4 takemura }
346 1.4 takemura }
347 1.4 takemura #endif /* LOAD_DEBUG_INFO */
348 1.4 takemura
349 1.4 takemura if (phtbl) free(phtbl, sizeof(*phtbl) * elf->e_phnum);
350 1.4 takemura if (shtbl) free(shtbl, sizeof(*shtbl) * elf->e_shnum);
351 1.4 takemura
352 1.4 takemura if (start) *start = min_addr;
353 1.4 takemura if (end) *end = max_addr;
354 1.4 takemura if (entry) *entry = (caddr_t)elf->e_entry;
355 1.4 takemura return (0);
356 1.4 takemura
357 1.4 takemura error_cleanup:
358 1.4 takemura if (phtbl) free(phtbl, sizeof(*phtbl) * elf->e_phnum);
359 1.4 takemura if (shtbl) free(shtbl, sizeof(*shtbl) * elf->e_shnum);
360 1.4 takemura return (-1);
361 1.4 takemura }
362