load_elf.cpp revision 1.16 1 /* $NetBSD: load_elf.cpp,v 1.16 2006/03/02 23:56:58 uwe Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <hpcmenu.h>
40 #include <menu/window.h>
41 #include <menu/rootwindow.h>
42
43 #include <load.h>
44 #include <load_elf.h>
45 #include <console.h>
46 #include <memory.h>
47 #include <file.h>
48
49 #define ROUND4(x) (((x) + 3) & ~3)
50
51 ElfLoader::ElfLoader(Console *&cons, MemoryManager *&mem)
52 : Loader(cons, mem)
53 {
54
55 _sym_blk.enable = FALSE;
56 _ph = NULL;
57 _sh = NULL;
58
59 DPRINTF((TEXT("Loader: ELF\n")));
60 }
61
62 ElfLoader::~ElfLoader(void)
63 {
64
65 if (_sym_blk.header != NULL)
66 free(_sym_blk.header);
67 if (_ph != NULL)
68 free(_ph);
69 if (_sh != NULL)
70 free(_sh);
71 }
72
73 BOOL
74 ElfLoader::setFile(File *&file)
75 {
76 size_t sz;
77 Loader::setFile(file);
78
79 // read ELF header and check it
80 if (!read_header())
81 return FALSE;
82
83 // read section header
84 sz = _eh.e_shnum * _eh.e_shentsize;
85 if ((_sh = static_cast<Elf_Shdr *>(malloc(sz))) == NULL) {
86 DPRINTF((TEXT("can't allocate section header table.\n")));
87 return FALSE;
88 }
89 if (_file->read(_sh, sz, _eh.e_shoff) != sz) {
90 DPRINTF((TEXT("section header read error.\n")));
91 return FALSE;
92 }
93
94 // read program header
95 sz = _eh.e_phnum * _eh.e_phentsize;
96 if ((_ph = static_cast<Elf_Phdr *>(malloc(sz))) == NULL) {
97 DPRINTF((TEXT("can't allocate program header table.\n")));
98 return FALSE;
99 }
100 if (_file->read(_ph, sz, _eh.e_phoff) != sz) {
101 DPRINTF((TEXT("program header read error.\n")));
102 return FALSE;
103 }
104
105 return TRUE;
106 }
107
108 size_t
109 ElfLoader::memorySize()
110 {
111 int i;
112 Elf_Phdr *ph = _ph;
113 size_t sz = 0;
114
115 DPRINTF((TEXT("file size: ")));
116 for (i = 0; i < _eh.e_phnum; i++, ph++) {
117 if (ph->p_type == PT_LOAD) {
118 size_t filesz = ph->p_filesz;
119 DPRINTF((TEXT("%s0x%x"),
120 sz == 0 ? "" : "+",
121 filesz));
122 sz += _mem->roundPage(filesz);
123 }
124 }
125
126 // reserve for symbols
127 size_t symblk_sz = symbol_block_size();
128 if (symblk_sz) {
129 sz += symblk_sz;
130 DPRINTF((TEXT(" = 0x%x]"), symblk_sz));
131 }
132
133 DPRINTF((TEXT(" = 0x%x bytes\n"), sz));
134 return sz;
135 }
136
137 kaddr_t
138 ElfLoader::jumpAddr()
139 {
140 DPRINTF((TEXT("kernel entry address: 0x%08x\n"), _eh.e_entry));
141 return _eh.e_entry;
142 }
143
144 BOOL
145 ElfLoader::load()
146 {
147 Elf_Phdr *ph;
148 vaddr_t kv;
149 int i;
150
151 _load_segment_start();
152
153 for (i = 0, ph = _ph; i < _eh.e_phnum; i++, ph++) {
154 if (ph->p_type == PT_LOAD) {
155 size_t filesz = ph->p_filesz;
156 size_t memsz = ph->p_memsz;
157 kv = ph->p_vaddr;
158 off_t fileofs = ph->p_offset;
159 DPRINTF((TEXT("seg[%d] vaddr 0x%08x file size 0x%x mem size 0x%x\n"),
160 i, kv, filesz, memsz));
161 _load_segment(kv, memsz, fileofs, filesz);
162 kv += ROUND4(memsz);
163 }
164 }
165
166 load_symbol_block(kv);
167
168 // tag chain still opening
169
170 return _load_success();
171 }
172
173 //
174 // Prepare ELF headers for symbol table.
175 //
176 // ELF header
177 // section header
178 // shstrtab
179 // symtab
180 // strtab
181 //
182 size_t
183 ElfLoader::symbol_block_size()
184 {
185 size_t shstrsize = ROUND4(_sh[_eh.e_shstrndx].sh_size);
186 size_t shtab_sz = _eh.e_shentsize * _eh.e_shnum;
187 off_t shstrtab_offset = sizeof(Elf_Ehdr) + shtab_sz;
188 int i;
189
190 memset(&_sym_blk, 0, sizeof(_sym_blk));
191 _sym_blk.enable = FALSE;
192 _sym_blk.header_size = sizeof(Elf_Ehdr) + shtab_sz + shstrsize;
193
194 // inquire string and symbol table size
195 _sym_blk.header = static_cast<char *>(malloc(_sym_blk.header_size));
196 if (_sym_blk.header == NULL) {
197 MessageBox(HPC_MENU._root->_window,
198 TEXT("Can't determine symbol block size."),
199 TEXT("WARNING"),
200 MB_ICONWARNING | MB_OK);
201 UpdateWindow(HPC_MENU._root->_window);
202 return (0);
203 }
204
205 // set pointer for symbol block
206 Elf_Ehdr *eh = reinterpret_cast<Elf_Ehdr *>(_sym_blk.header);
207 Elf_Shdr *sh = reinterpret_cast<Elf_Shdr *>
208 (_sym_blk.header + sizeof(Elf_Ehdr));
209 char *shstrtab = _sym_blk.header + shstrtab_offset;
210
211 // initialize headers
212 memset(_sym_blk.header, 0, _sym_blk.header_size);
213 memcpy(eh, &_eh, sizeof(Elf_Ehdr));
214 eh->e_phoff = 0;
215 eh->e_phnum = 0;
216 eh->e_entry = 0; // XXX NetBSD kernel check this member. see machdep.c
217 eh->e_shoff = sizeof(Elf_Ehdr);
218 memcpy(sh, _sh, shtab_sz);
219
220 // inquire symbol/string table information
221 _file->read(shstrtab, shstrsize, _sh[_eh.e_shstrndx].sh_offset);
222 for (i = 0; i < _eh.e_shnum; i++, sh++) {
223 if (strcmp(".strtab", shstrtab + sh->sh_name) == 0) {
224 _sym_blk.shstr = sh;
225 _sym_blk.stroff = sh->sh_offset;
226 } else if (strcmp(".symtab", shstrtab + sh->sh_name) == 0) {
227 _sym_blk.shsym = sh;
228 _sym_blk.symoff = sh->sh_offset;
229 }
230
231 sh->sh_offset = (i == _eh.e_shstrndx) ? shstrtab_offset : 0;
232 }
233
234 if (_sym_blk.shstr == NULL || _sym_blk.shsym == NULL) {
235 if (HPC_PREFERENCE.safety_message) {
236 MessageBox(HPC_MENU._root->_window,
237 TEXT("No symbol and/or string table in binary.\n(not fatal)"),
238 TEXT("Information"),
239 MB_ICONINFORMATION | MB_OK);
240 UpdateWindow(HPC_MENU._root->_window);
241 }
242 free(_sym_blk.header);
243 _sym_blk.header = NULL;
244
245 return (0);
246 }
247
248 // set Section Headers for symbol/string table
249 _sym_blk.shsym->sh_offset = shstrtab_offset + shstrsize;
250 _sym_blk.shstr->sh_offset = shstrtab_offset + shstrsize +
251 ROUND4(_sym_blk.shsym->sh_size);
252 _sym_blk.enable = TRUE;
253
254 DPRINTF((TEXT("+[ksyms: header 0x%x, symtab 0x%x, strtab 0x%x"),
255 _sym_blk.header_size, _sym_blk.shsym->sh_size,
256 _sym_blk.shstr->sh_size));
257
258 // return total amount of symbol block
259 return (_sym_blk.header_size + ROUND4(_sym_blk.shsym->sh_size) +
260 _sym_blk.shstr->sh_size);
261 }
262
263 void
264 ElfLoader::load_symbol_block(vaddr_t kv)
265 {
266 size_t sz;
267
268 if (!_sym_blk.enable)
269 return;
270
271 DPRINTF((TEXT("ksyms\n")));
272
273 // load header
274 _load_memory(kv, _sym_blk.header_size, _sym_blk.header);
275 kv += _sym_blk.header_size;
276
277 // load symbol table
278 sz = _sym_blk.shsym->sh_size;
279 _load_segment(kv, sz, _sym_blk.symoff, sz);
280 kv += ROUND4(sz);
281
282 // load string table
283 sz = _sym_blk.shstr->sh_size;
284 _load_segment(kv, sz, _sym_blk.stroff, sz);
285 }
286
287 BOOL
288 ElfLoader::read_header()
289 {
290 // read ELF header
291 _file->read(&_eh, sizeof(Elf_Ehdr), 0);
292
293 // check ELF Magic.
294 if (!is_elf_file()) {
295 DPRINTF((TEXT("not a ELF file.\n")));
296 return FALSE;
297 }
298
299 // Windows CE is 32bit little-endian only.
300 if (_eh.e_ident[EI_DATA] != ELFDATA2LSB ||
301 _eh.e_ident[EI_CLASS] != ELFCLASS32) {
302 DPRINTF((TEXT("invalid class/data(%d/%d)\n"),
303 _eh.e_ident[EI_CLASS], _eh.e_ident[EI_DATA]));
304 return FALSE;
305 }
306
307 // Is native architecture?
308 switch(_eh.e_machine) {
309 ELF32_MACHDEP_ID_CASES;
310 default:
311 DPRINTF((TEXT("not a native architecture. machine = %d\n"),
312 _eh.e_machine));
313 return FALSE;
314 }
315
316 // Check object type
317 if (_eh.e_type != ET_EXEC) {
318 DPRINTF((TEXT("not a executable file. type = %d\n"),
319 _eh.e_type));
320 return FALSE;
321 }
322
323 if (_eh.e_phoff == 0 || _eh.e_phnum == 0 || _eh.e_phnum > 16 ||
324 _eh.e_phentsize != sizeof(Elf_Phdr)) {
325 DPRINTF((TEXT("invalid program header information.\n")));
326 return FALSE;
327 }
328
329 return TRUE;
330 }
331