1 /* $NetBSD: elf.c,v 1.8 2007/03/04 05:59:53 christos Exp $ */
4 * Copyright (c) 1999 Shin Takemura.
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
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
41 //#include <sys/param.h>
42 //#include <sys/exec.h>
43 #include <sys/exec_elf.h>
46 #define LOAD_DEBUG_INFO
47 #define DEBUG_INFO_ALIGN 4096
48 #define ROUNDUP(a, n) ((((int)(a)) + (n)-1)/(n)*(n))
52 scanfile(int fd
, void **start
, void **end
, void **entry
, int load
);
54 static long total_bytes
= 0;
57 getinfo(int fd
, void **start
, void **end
)
59 return (scanfile(fd
, start
, end
, NULL
, 0));
63 loadfile(int fd
, void **entry
)
65 return (scanfile(fd
, NULL
, NULL
, entry
, 1));
69 VMEM_CLEAR
, VMEM_LOAD
, VMEM_COPY
73 vmem_sub(int opr
, void* xxx
, void *addr
, int nbytes
, int *byte_count
)
76 void *end_addr
, *vaddr
;
80 void *src_addr
= (void *)xxx
;
82 debug_printf(TEXT("loadfile_sub(%x-%x, %S)\n"),
84 opr
== VMEM_CLEAR
? "clear" : (opr
== VMEM_LOAD
? "load" : "copy"));
86 for (end_addr
= addr
+ nbytes
;
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
);
94 if (end_addr
< addr
+ n
) {
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"));
109 memcpy(vaddr
, src_addr
, n
);
113 if (total_bytes
!= 0) {
114 int tmp_progress
= *byte_count
* 100 / total_bytes
;
116 if (progress
!= tmp_progress
) {
117 progress
= tmp_progress
;
118 if (CheckCancel(progress
)) {
129 scanfile(int fd
, void **start
, void **end
, void **entry
, int load
)
131 Elf_Ehdr elfx
, *elf
= &elfx
;
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"));
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"));
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"));
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"));
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"));
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"));
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"));
184 * scan program header table
189 for (i
= 0; i
< elf
->e_phnum
; i
++) {
190 if (phtbl
[i
].p_type
!= PT_LOAD
) {
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
;
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"));
208 if (vmem_sub(VMEM_LOAD
, (void*)fd
,
209 (void *)phtbl
[i
].p_vaddr
,
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
,
221 byte_count
+= phtbl
[i
].p_memsz
;
228 debug_printf(TEXT("can't find loadable segment\n"));
229 msg_printf(MSG_ERROR
, whoami
, TEXT("can't find loadable segment\n"));
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
245 for (i
= 0; i
< elf
->e_shnum
; i
++) {
246 if (shtbl
[i
].sh_type
== SHT_SYMTAB
) {
249 if ((shtbl
[i
].sh_type
== SHT_STRTAB
)
250 && (shtbl
[i
].sh_size
>= 0x4000)) {
254 if (sh_symidx
== -1 || sh_stridx
== -1) {
255 debug_printf(TEXT("debugging information not found\n"));
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
;
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;
274 dbg_eh
.e_shentsize
= sizeof(Elf_Shdr
);
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
,
286 if (vmem_sub(VMEM_COPY
, (void*)&dbg_eh
,
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,
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"));
314 if (vmem_sub(VMEM_LOAD
, (void*)fd
,
315 max_addr
+ dbg_hdr_size
,
316 shtbl
[sh_symidx
].sh_size
,
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"));
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
,
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
,
341 debug_printf(TEXT("%x bytes debug information\n"),
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
;
358 if (phtbl
) dealloc(phtbl
, sizeof(*phtbl
) * elf
->e_phnum
);
359 if (shtbl
) dealloc(shtbl
, sizeof(*shtbl
) * elf
->e_shnum
);