1 /* $NetBSD: load_elf.cpp,v 1.18 2008/04/28 20:23:20 martin Exp $ */
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 #include <menu/window.h>
34 #include <menu/rootwindow.h>
42 #define ROUND4(x) (((x) + 3) & ~3)
44 ElfLoader::ElfLoader(Console
*&cons
, MemoryManager
*&mem
)
48 _sym_blk
.enable
= FALSE
;
52 DPRINTF((TEXT("Loader: ELF\n")));
55 ElfLoader::~ElfLoader(void)
58 if (_sym_blk
.header
!= NULL
)
59 free(_sym_blk
.header
);
67 ElfLoader::setFile(File
*&file
)
70 Loader::setFile(file
);
72 // read ELF header and check it
76 // read section header
77 sz
= _eh
.e_shnum
* _eh
.e_shentsize
;
78 if ((_sh
= static_cast<Elf_Shdr
*>(malloc(sz
))) == NULL
) {
79 DPRINTF((TEXT("can't allocate section header table.\n")));
82 if (_file
->read(_sh
, sz
, _eh
.e_shoff
) != sz
) {
83 DPRINTF((TEXT("section header read error.\n")));
87 // read program header
88 sz
= _eh
.e_phnum
* _eh
.e_phentsize
;
89 if ((_ph
= static_cast<Elf_Phdr
*>(malloc(sz
))) == NULL
) {
90 DPRINTF((TEXT("can't allocate program header table.\n")));
93 if (_file
->read(_ph
, sz
, _eh
.e_phoff
) != sz
) {
94 DPRINTF((TEXT("program header read error.\n")));
102 ElfLoader::memorySize()
109 DPRINTF((TEXT("file size: ")));
110 for (i
= 0; i
< _eh
.e_phnum
; i
++, ph
++) {
111 if (ph
->p_type
== PT_LOAD
) {
112 size_t filesz
= ph
->p_filesz
;
113 DPRINTF((TEXT("%s0x%x"),
116 sz
+= _mem
->roundPage(filesz
);
117 // compensate for partial last tag
118 extra
+= _mem
->getTaggedPageSize();
119 if (filesz
< ph
->p_memsz
)
120 // compensate for zero clear
121 extra
+= _mem
->getTaggedPageSize();
126 // reserve for symbols
127 size_t symblk_sz
= symbol_block_size();
130 DPRINTF((TEXT(" = 0x%x]"), symblk_sz
));
131 // XXX: compensate for partial tags after ELF header and symtab
132 extra
+= 2 * _mem
->getTaggedPageSize();
136 DPRINTF((TEXT("+[extra: 0x%x]"), extra
));
138 DPRINTF((TEXT(" = 0x%x bytes\n"), sz
));
143 ElfLoader::jumpAddr()
145 DPRINTF((TEXT("kernel entry address: 0x%08x\n"), _eh
.e_entry
));
156 _load_segment_start();
158 for (i
= 0, ph
= _ph
; i
< _eh
.e_phnum
; i
++, ph
++) {
159 if (ph
->p_type
== PT_LOAD
) {
160 size_t filesz
= ph
->p_filesz
;
161 size_t memsz
= ph
->p_memsz
;
163 off_t fileofs
= ph
->p_offset
;
164 DPRINTF((TEXT("seg[%d] paddr 0x%08x file size 0x%x mem size 0x%x\n"),
165 i
, kv
, filesz
, memsz
));
166 _load_segment(kv
, memsz
, fileofs
, filesz
);
171 load_symbol_block(kv
);
173 // tag chain still opening
175 return _load_success();
179 // Prepare ELF headers for symbol table.
188 ElfLoader::symbol_block_size()
190 size_t shstrsize
= ROUND4(_sh
[_eh
.e_shstrndx
].sh_size
);
191 size_t shtab_sz
= _eh
.e_shentsize
* _eh
.e_shnum
;
192 off_t shstrtab_offset
= sizeof(Elf_Ehdr
) + shtab_sz
;
195 memset(&_sym_blk
, 0, sizeof(_sym_blk
));
196 _sym_blk
.enable
= FALSE
;
197 _sym_blk
.header_size
= sizeof(Elf_Ehdr
) + shtab_sz
+ shstrsize
;
199 // inquire string and symbol table size
200 _sym_blk
.header
= static_cast<char *>(malloc(_sym_blk
.header_size
));
201 if (_sym_blk
.header
== NULL
) {
202 MessageBox(HPC_MENU
._root
->_window
,
203 TEXT("Can't determine symbol block size."),
205 MB_ICONWARNING
| MB_OK
);
206 UpdateWindow(HPC_MENU
._root
->_window
);
210 // set pointer for symbol block
211 Elf_Ehdr
*eh
= reinterpret_cast<Elf_Ehdr
*>(_sym_blk
.header
);
212 Elf_Shdr
*sh
= reinterpret_cast<Elf_Shdr
*>
213 (_sym_blk
.header
+ sizeof(Elf_Ehdr
));
214 char *shstrtab
= _sym_blk
.header
+ shstrtab_offset
;
216 // initialize headers
217 memset(_sym_blk
.header
, 0, _sym_blk
.header_size
);
218 memcpy(eh
, &_eh
, sizeof(Elf_Ehdr
));
221 eh
->e_entry
= 0; // XXX NetBSD kernel check this member. see machdep.c
222 eh
->e_shoff
= sizeof(Elf_Ehdr
);
223 memcpy(sh
, _sh
, shtab_sz
);
225 // inquire symbol/string table information
226 _file
->read(shstrtab
, shstrsize
, _sh
[_eh
.e_shstrndx
].sh_offset
);
227 for (i
= 0; i
< _eh
.e_shnum
; i
++, sh
++) {
228 if (strcmp(".strtab", shstrtab
+ sh
->sh_name
) == 0) {
230 _sym_blk
.stroff
= sh
->sh_offset
;
231 } else if (strcmp(".symtab", shstrtab
+ sh
->sh_name
) == 0) {
233 _sym_blk
.symoff
= sh
->sh_offset
;
236 sh
->sh_offset
= (i
== _eh
.e_shstrndx
) ? shstrtab_offset
: 0;
239 if (_sym_blk
.shstr
== NULL
|| _sym_blk
.shsym
== NULL
) {
240 if (HPC_PREFERENCE
.safety_message
) {
241 MessageBox(HPC_MENU
._root
->_window
,
242 TEXT("No symbol and/or string table in binary.\n(not fatal)"),
244 MB_ICONINFORMATION
| MB_OK
);
245 UpdateWindow(HPC_MENU
._root
->_window
);
247 free(_sym_blk
.header
);
248 _sym_blk
.header
= NULL
;
253 // set Section Headers for symbol/string table
254 _sym_blk
.shsym
->sh_offset
= shstrtab_offset
+ shstrsize
;
255 _sym_blk
.shstr
->sh_offset
= shstrtab_offset
+ shstrsize
+
256 ROUND4(_sym_blk
.shsym
->sh_size
);
257 _sym_blk
.enable
= TRUE
;
259 DPRINTF((TEXT("+[ksyms: header 0x%x, symtab 0x%x, strtab 0x%x"),
260 _sym_blk
.header_size
, _sym_blk
.shsym
->sh_size
,
261 _sym_blk
.shstr
->sh_size
));
263 // return total amount of symbol block
264 return (_sym_blk
.header_size
+ ROUND4(_sym_blk
.shsym
->sh_size
) +
265 _sym_blk
.shstr
->sh_size
);
269 ElfLoader::load_symbol_block(vaddr_t kv
)
273 if (!_sym_blk
.enable
)
276 DPRINTF((TEXT("ksyms\n")));
279 _load_memory(kv
, _sym_blk
.header_size
, _sym_blk
.header
);
280 kv
+= _sym_blk
.header_size
;
283 sz
= _sym_blk
.shsym
->sh_size
;
284 _load_segment(kv
, sz
, _sym_blk
.symoff
, sz
);
288 sz
= _sym_blk
.shstr
->sh_size
;
289 _load_segment(kv
, sz
, _sym_blk
.stroff
, sz
);
293 ElfLoader::read_header()
296 _file
->read(&_eh
, sizeof(Elf_Ehdr
), 0);
299 if (!is_elf_file()) {
300 DPRINTF((TEXT("not a ELF file.\n")));
304 // Windows CE is 32bit little-endian only.
305 if (_eh
.e_ident
[EI_DATA
] != ELFDATA2LSB
||
306 _eh
.e_ident
[EI_CLASS
] != ELFCLASS32
) {
307 DPRINTF((TEXT("invalid class/data(%d/%d)\n"),
308 _eh
.e_ident
[EI_CLASS
], _eh
.e_ident
[EI_DATA
]));
312 // Is native architecture?
313 switch(_eh
.e_machine
) {
314 ELF32_MACHDEP_ID_CASES
;
316 DPRINTF((TEXT("not a native architecture. machine = %d\n"),
322 if (_eh
.e_type
!= ET_EXEC
) {
323 DPRINTF((TEXT("not a executable file. type = %d\n"),
328 if (_eh
.e_phoff
== 0 || _eh
.e_phnum
== 0 || _eh
.e_phnum
> 16 ||
329 _eh
.e_phentsize
!= sizeof(Elf_Phdr
)) {
330 DPRINTF((TEXT("invalid program header information.\n")));