#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
#ifdef __NetBSD__
#define ELFSIZE 64
#include <sys/exec_elf.h>
#else
#include <sys/elf64.h>
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Phdr Elf64_Phdr
#endif
#define ELF_MAXPHNUM 128
#define ELF_MAXSHNUM 32768
static int
elf_check_header(Elf_Ehdr *eh)
{
if (eh->e_shnum > ELF_MAXSHNUM || eh->e_phnum > ELF_MAXPHNUM)
return -1;
return 0;
}
static uint64_t
elf_parse(struct nvmm_machine *mach, char *base)
{
Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
Elf_Phdr *phdr;
uintptr_t hva;
gpaddr_t lastgpa;
size_t i;
if (elf_check_header(ehdr) == -1)
errx(EXIT_FAILURE, "wrong ELF header");
phdr = (Elf_Phdr *)((char *)ehdr + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++) {
if (phdr[i].p_type != PT_LOAD) {
if (phdr[i].p_filesz == 0) {
continue;
} else {
errx(EXIT_FAILURE, "unsupported ELF");
}
}
hva = toyvirt_mem_add(mach, phdr[i].p_vaddr,
roundup(phdr[i].p_filesz, PAGE_SIZE));
memcpy((void *)hva, base + phdr[i].p_offset, phdr[i].p_filesz);
lastgpa = phdr[i].p_vaddr +
roundup(phdr[i].p_filesz, PAGE_SIZE);
}
toyvirt_mem_add(mach, lastgpa, 128 * PAGE_SIZE);
return ehdr->e_entry;
}
int
elf_map(struct nvmm_machine *mach, const char *path, uint64_t *rip)
{
struct stat st;
char *base = NULL;
int fd, ret = -1;
fd = open(path, O_RDONLY);
if (fstat(fd, &st) == -1)
goto out;
if ((size_t)st.st_size < sizeof(Elf_Ehdr))
goto out;
base = malloc(st.st_size);
pread(fd, base, st.st_size, 0);
*rip = elf_parse(mach, base);
ret = 0;
out:
close(fd);
free(base);
return ret;
}