// Copyright (c) 2010-2017, The Regents of the University of California // (Regents). All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // 3. Neither the name of the Regents nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING // OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS // BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED // HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE // MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #include <svdpi.h> #include <cstring> #include <string> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <assert.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <vector> #include <map> #include <iostream> #include <stdint.h> #define IS_ELF(hdr) \ ((hdr).e_ident[0] == 0x7f && (hdr).e_ident[1] == 'E' && \ (hdr).e_ident[2] == 'L' && (hdr).e_ident[3] == 'F') #define IS_ELF32(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 1) #define IS_ELF64(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 2) #define PT_LOAD 1 #define SHT_NOBITS 8 #define SHT_PROGBITS 0x1 #define SHT_GROUP 0x11 typedef struct { uint8_t e_ident[16]; uint16_t e_type; uint16_t e_machine; uint32_t e_version; uint32_t e_entry; uint32_t e_phoff; uint32_t e_shoff; uint32_t e_flags; uint16_t e_ehsize; uint16_t e_phentsize; uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; uint16_t e_shstrndx; } Elf32_Ehdr; typedef struct { uint32_t sh_name; uint32_t sh_type; uint32_t sh_flags; uint32_t sh_addr; uint32_t sh_offset; uint32_t sh_size; uint32_t sh_link; uint32_t sh_info; uint32_t sh_addralign; uint32_t sh_entsize; } Elf32_Shdr; typedef struct { uint32_t p_type; uint32_t p_offset; uint32_t p_vaddr; uint32_t p_paddr; uint32_t p_filesz; uint32_t p_memsz; uint32_t p_flags; uint32_t p_align; } Elf32_Phdr; typedef struct { uint32_t st_name; uint32_t st_value; uint32_t st_size; uint8_t st_info; uint8_t st_other; uint16_t st_shndx; } Elf32_Sym; typedef struct { uint8_t e_ident[16]; uint16_t e_type; uint16_t e_machine; uint32_t e_version; uint64_t e_entry; uint64_t e_phoff; uint64_t e_shoff; uint32_t e_flags; uint16_t e_ehsize; uint16_t e_phentsize; uint16_t e_phnum; uint16_t e_shentsize; uint16_t e_shnum; uint16_t e_shstrndx; } Elf64_Ehdr; typedef struct { uint32_t sh_name; uint32_t sh_type; uint64_t sh_flags; uint64_t sh_addr; uint64_t sh_offset; uint64_t sh_size; uint32_t sh_link; uint32_t sh_info; uint64_t sh_addralign; uint64_t sh_entsize; } Elf64_Shdr; typedef struct { uint32_t p_type; uint32_t p_flags; uint64_t p_offset; uint64_t p_vaddr; uint64_t p_paddr; uint64_t p_filesz; uint64_t p_memsz; uint64_t p_align; } Elf64_Phdr; typedef struct { uint32_t st_name; uint8_t st_info; uint8_t st_other; uint16_t st_shndx; uint64_t st_value; uint64_t st_size; } Elf64_Sym; // address and size std::vector<std::pair<uint64_t, uint64_t>> sections; std::map<std::string, uint64_t> symbols; // memory based address and content std::map<uint64_t, std::vector<uint8_t>> mems; uint64_t entry; int section_index = 0; static void write (uint64_t address, uint64_t len, uint8_t* buf) { uint64_t datum; std::vector<uint8_t> mem; for (int i = 0; i < len; i++) { mem.push_back(buf[i]); } mems.insert(std::make_pair(address, mem)); } extern "C" { char get_section(long long* address, long long* len); char read_section(long long address, const svOpenArrayHandle buffer); void read_elf(const char* filename); } // Communicate the section address and len // Returns: // 0 if there are no more sections // 1 if there are more sections to load extern "C" char get_section(long long* address, long long* len) { if (section_index < sections.size()) { *address = sections[section_index].first; *len = sections[section_index].second; section_index++; return 1; } else { return 0; } } extern "C" char read_section(long long address, const svOpenArrayHandle buffer) { // get actual poitner void* buf = svGetArrayPtr(buffer); // check that the address points to a section assert(mems.count(address) > 0); // copy array int i = 0; for (auto &datum : mems.find(address)->second) { *((char *) buf + i) = datum; i++; } return 0; } extern "C" void read_elf(const char* filename) { int fd = open(filename, O_RDONLY); struct stat s; assert(fd != -1); if (fstat(fd, &s) < 0) abort(); size_t size = s.st_size; char* buf = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); assert(buf != MAP_FAILED); close(fd); assert(size >= sizeof(Elf64_Ehdr)); const Elf64_Ehdr* eh64 = (const Elf64_Ehdr*)buf; assert(IS_ELF32(*eh64) || IS_ELF64(*eh64)); std::vector<uint8_t> zeros; std::map<std::string, uint64_t> symbols; #define LOAD_ELF(ehdr_t, phdr_t, shdr_t, sym_t) do { \ ehdr_t* eh = (ehdr_t*)buf; \ phdr_t* ph = (phdr_t*)(buf + eh->e_phoff); \ entry = eh->e_entry; \ assert(size >= eh->e_phoff + eh->e_phnum*sizeof(*ph)); \ for (unsigned i = 0; i < eh->e_phnum; i++) { \ if(ph[i].p_type == PT_LOAD && ph[i].p_memsz) { \ if (ph[i].p_filesz) { \ assert(size >= ph[i].p_offset + ph[i].p_filesz); \ sections.push_back(std::make_pair(ph[i].p_paddr, ph[i].p_memsz)); \ write(ph[i].p_paddr, ph[i].p_filesz, (uint8_t*)buf + ph[i].p_offset); \ } \ zeros.resize(ph[i].p_memsz - ph[i].p_filesz); \ } \ } \ shdr_t* sh = (shdr_t*)(buf + eh->e_shoff); \ assert(size >= eh->e_shoff + eh->e_shnum*sizeof(*sh)); \ assert(eh->e_shstrndx < eh->e_shnum); \ assert(size >= sh[eh->e_shstrndx].sh_offset + sh[eh->e_shstrndx].sh_size); \ char *shstrtab = buf + sh[eh->e_shstrndx].sh_offset; \ unsigned strtabidx = 0, symtabidx = 0; \ for (unsigned i = 0; i < eh->e_shnum; i++) { \ unsigned max_len = sh[eh->e_shstrndx].sh_size - sh[i].sh_name; \ if ((sh[i].sh_type & SHT_GROUP) && strcmp(shstrtab + sh[i].sh_name, ".strtab") != 0 && strcmp(shstrtab + sh[i].sh_name, ".shstrtab") != 0) \ assert(strnlen(shstrtab + sh[i].sh_name, max_len) < max_len); \ if (sh[i].sh_type & SHT_PROGBITS) continue; \ if (strcmp(shstrtab + sh[i].sh_name, ".strtab") == 0) \ strtabidx = i; \ if (strcmp(shstrtab + sh[i].sh_name, ".symtab") == 0) \ symtabidx = i; \ } \ if (strtabidx && symtabidx) { \ char* strtab = buf + sh[strtabidx].sh_offset; \ sym_t* sym = (sym_t*)(buf + sh[symtabidx].sh_offset); \ for (unsigned i = 0; i < sh[symtabidx].sh_size/sizeof(sym_t); i++) { \ unsigned max_len = sh[strtabidx].sh_size - sym[i].st_name; \ assert(sym[i].st_name < sh[strtabidx]. sh_size); \ assert(strnlen(strtab + sym[i].st_name, max_len) < max_len); \ symbols[strtab + sym[i].st_name] = sym[i].st_value; \ } \ } \ } while(0) if (IS_ELF32(*eh64)) LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym); else LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym); munmap(buf, size); }