/* $NetBSD: exec_sub.c,v 1.6 2009/03/14 21:04:17 dsl Exp $ */
#include <sys/cdefs.h>
#include "execkern.h"
#include <a.out.h>
#include <sys/param.h>
#ifdef BOOT
void B_PRINT(const unsigned char *p);
#endif
static inline void bzero4(void *ptr, size_t siz);
static void xk_aout(struct execkern_arg *xarg, struct exec *hdr);
static void xk_elf(struct execkern_arg *xarg, Elf32_Ehdr *hdr);
#ifdef LOADBSD
static void DPRINT_SEC(const char *ident,
const struct execkern_section *sec);
extern int opt_v;
extern const char *kernel_fn;
static void
DPRINT_SEC(const char *ident, const struct execkern_section *sec)
{
if (opt_v)
xwarnx("section (%s): img %p, sz %d, pad %d", ident,
sec->sec_image, sec->sec_size, sec->sec_pad);
}
#define ERRX(arg) xerrx arg
#else
#define DPRINT_SEC(ident, sec) /**/
#define ERRX(arg) return 1
#endif
/*
* This code is size-hacked version of
*
* sec->sec_image = (image);
* sec->sec_size = (size);
* sec->sec_pad = (pad);
* DPRINT_SEC((ident), sec);
* sec++;
*/
#define SECTION(sec, ident, image, size, pad) \
do { \
u_long *wp = (void *) sec; \
*(void **)wp++ = (image); \
*wp++ = (size); \
*wp++ = (pad); \
DPRINT_SEC((ident), sec); \
sec = (void *) wp; \
} while (0)
#define SECTION_NOPAD(sec, ident, image, size) \
SECTION(sec, (ident), (image), (size), 0)
static inline void
bzero4(void *ptr, size_t siz)
{
u_long *p;
u_short s;
p = ptr;
s = siz >> 2;
while (s--)
*p++ = 0;
}
/*
* fill in loading information from an a.out executable
*/
static void
xk_aout(struct execkern_arg *xarg, struct exec *hdr)
{
unsigned u;
char *s;
struct execkern_section *sec;
xarg->entry_addr = hdr->a_entry;
sec = xarg->sec;
/* text section and padding between data section */
s = (void *) (hdr + 1);
SECTION(sec, "text", s, hdr->a_text, -hdr->a_text & (AOUT_LDPGSZ-1));
/* data and bss sections */
s += hdr->a_text;
SECTION(sec, "data/bss", s, hdr->a_data, hdr->a_bss);
/* size of symbol table */
SECTION_NOPAD(sec, "symtab size", &sec[1].sec_size, sizeof(u_long));
/* symbol table section */
s += hdr->a_data;
SECTION_NOPAD(sec, "symbol", s, u = hdr->a_syms);
/* string table section */
if (u) {
#ifdef LOADBSD
if (opt_v)
xwarnx("symbol table found");
#endif
s += u;
SECTION_NOPAD(sec, "string", s, *(u_long *) s);
}
}
/*
* fill in loading information from an ELF executable
*/
static void
xk_elf(struct execkern_arg *xarg, Elf32_Ehdr *hdr)
{
char *top = (void *) hdr;
struct execkern_section *sec;
Elf32_Phdr *ph;
Elf32_Shdr *sh, *sym, *str, *stab, *shstr;
const char *shstrtab, *shname;
unsigned u, dpos, pd;
const char *const shstrtab_new = SHSTRTAB_FAKE;
xarg->entry_addr = hdr->e_entry;
/*
* text, data, bss
*/
ph = (void *) (top + hdr->e_phoff);
xarg->load_addr = ph->p_vaddr;
sec = xarg->sec;
sec->sec_image = top + ph->p_offset;
sec->sec_size = ph->p_filesz;
if (hdr->e_phnum != 1) {
sec->sec_pad = ph[1].p_vaddr - (ph->p_vaddr + ph->p_filesz);
DPRINT_SEC("program (text)", sec);
sec++;
ph++;
sec->sec_image = top + ph->p_offset;
sec->sec_size = ph->p_filesz;
}
sec->sec_pad = ph->p_memsz - ph->p_filesz;
DPRINT_SEC("program (data/bss)", sec);
sec++;
/*
* symbol size
*/
xarg->elfsymsiz = 0; /* no symbol */
SECTION_NOPAD(sec, "symtab size", &xarg->elfsymsiz, sizeof(int));
/*
* ELF header
*/
xarg->ehdr = *hdr;
xarg->ehdr.e_shstrndx = 0; /* .shstrtab will be the 1st section */
SECTION_NOPAD(sec, "ELF header", &xarg->ehdr, sizeof(Elf32_Ehdr));
sh = (void *) (top + hdr->e_shoff); /* section header */
shstr = sh + hdr->e_shstrndx; /* .shstrtab */
shstrtab = top + shstr->sh_offset;
sym = str = stab = 0;
for (u = 0; sh++, ++u < hdr->e_shnum; ) {
shname = shstrtab + sh->sh_name;
if (!strcmp(shname, shstrtab_new + SHNAME_OFF_SYMTAB))
sym = sh; /* .symtab */
if (!strcmp(shname, shstrtab_new + SHNAME_OFF_STRTAB))
str = sh; /* .strtab */
if (!strcmp(shname, shstrtab_new + SHNAME_OFF_STAB))
stab = sh; /* .stab */
}
if (shstr == 0 || sym == 0 || str == 0)
xarg->ehdr.e_shnum = 0; /* no symbol */
else {
#ifdef LOADBSD
if (opt_v) {
xwarnx("symbol table found");
if (stab)
xwarnx("debugging information found");
}
#endif
xarg->elfsymsiz = 1; /* has symbol */
xarg->ehdr.e_shnum = 3;
xarg->ehdr.e_shoff = sizeof(Elf32_Ehdr);
SECTION_NOPAD(sec, "section header (shstrtab)",
shstr, sizeof(Elf32_Shdr));
SECTION_NOPAD(sec, "section header (symbol)",
sym, sizeof(Elf32_Shdr));
SECTION_NOPAD(sec, "section header (string)",
str, sizeof(Elf32_Shdr));
dpos = sizeof(Elf32_Ehdr) + sizeof(Elf32_Shdr) * 3;
u = SIZE_SHSTRTAB_FAKE;
if (stab) {
xarg->ehdr.e_shnum++;
SECTION_NOPAD(sec, "section header (stab)",
stab, sizeof(Elf32_Shdr));
dpos += sizeof(Elf32_Shdr);
u = SIZE_SHSTRTAB_FAKE_WITH_STAB;
}
/* new .shstrtab section */
memcpy(xarg->shstrtab_fake, shstrtab_new, u);
/*
* DDB requires symtab be aligned.
*/
pd = -u & ALIGNBYTES;
SECTION(sec, "shstrtab", &xarg->shstrtab_fake, u, pd);
shstr->sh_name = SHNAME_OFF_SHSTRTAB;
shstr->sh_offset = dpos;
dpos += u + pd;
SECTION_NOPAD(sec, "symtab",
top + sym->sh_offset, sym->sh_size);
sym->sh_name = SHNAME_OFF_SYMTAB;
sym->sh_offset = dpos;
dpos += sym->sh_size;
SECTION_NOPAD(sec, "strtab",
top + str->sh_offset, str->sh_size);
str->sh_name = SHNAME_OFF_STRTAB;
str->sh_offset = dpos;
dpos += str->sh_size;
if (stab) {
SECTION_NOPAD(sec, "stab",
top + stab->sh_offset, stab->sh_size);
stab->sh_name = SHNAME_OFF_STAB;
stab->sh_offset = dpos;
}
}
}
int
xk_load(struct execkern_arg *xarg, void *buf, u_long loadaddr)
/* loadaddr: for a.out */
{
struct exec *ahdr;
Elf32_Ehdr *ehdr;
unsigned u;
/* Unused section entries should be cleared to zero. */
bzero4(xarg->sec, sizeof xarg->sec);
xarg->load_addr = loadaddr;
/*
* check exec header
*/
ahdr = buf;
ehdr = buf;
if (N_GETMAGIC(*ahdr) == NMAGIC) {
/*
* this is an a.out
*/
#ifdef LOADBSD
if (opt_v)
xwarnx("%s: is an a.out", kernel_fn);
#endif
#ifdef BOOT
B_PRINT("This is an a.out\r\n");
#endif
if ((u = N_GETMID(*ahdr)) != MID_M68K)
ERRX((1, "%s: Wrong architecture (mid %u)",
kernel_fn, u));
/*
* fill in loading information
*/
xk_aout(xarg, ahdr);
} else {
/*
* check ELF header
*/
if (*(u_int32_t *)&ehdr->e_ident[EI_MAG0] !=
(ELFMAG0<<24 | ELFMAG1<<16 | ELFMAG2<<8 | ELFMAG3) ||
*(u_int16_t *)&ehdr->e_ident[EI_CLASS] !=
(ELFCLASS32 << 8 | ELFDATA2MSB))
ERRX((1, "%s: Not an NMAGIC a.out or a 32bit BE ELF",
kernel_fn));
/*
* this is an ELF
*/
#ifdef LOADBSD
if (opt_v)
xwarnx("%s: is an ELF", kernel_fn);
#endif
#ifdef BOOT
B_PRINT("This is an ELF\r\n");
#endif
if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
ehdr->e_version != EV_CURRENT)
ERRX((1, "%s: Unsupported ELF version", kernel_fn));
if ((u = ehdr->e_machine) != EM_68K)
ERRX((1, "%s: Wrong architecture (mid %u)",
kernel_fn, u));
if (ehdr->e_type != ET_EXEC)
ERRX((1, "%s: Not an executable", kernel_fn));
if ((u = ehdr->e_phnum) != 1 && u != 2)
ERRX((1, "%s: Wrong number (%u) of loading sections",
kernel_fn, u));
/*
* fill in loading information
*/
xk_elf(xarg, ehdr);
}
return 0;
}