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