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