Home | History | Annotate | Line # | Download | only in common
      1 /*	$NetBSD: exec_sub.c,v 1.6 2009/03/14 21:04:17 dsl Exp $ */
      2 
      3 #include <sys/cdefs.h>
      4 
      5 #include "execkern.h"
      6 #include <a.out.h>
      7 #include <sys/param.h>
      8 
      9 #ifdef BOOT
     10 void B_PRINT(const unsigned char *p);
     11 #endif
     12 
     13 static inline void bzero4(void *ptr, size_t siz);
     14 static void xk_aout(struct execkern_arg *xarg, struct exec *hdr);
     15 static void xk_elf(struct execkern_arg *xarg, Elf32_Ehdr *hdr);
     16 
     17 #ifdef LOADBSD
     18 static void DPRINT_SEC(const char *ident,
     19 			    const struct execkern_section *sec);
     20 extern int opt_v;
     21 extern const char *kernel_fn;
     22 
     23 static void
     24 DPRINT_SEC(const char *ident, const struct execkern_section *sec)
     25 {
     26 
     27 	if (opt_v)
     28 		xwarnx("section (%s): img %p, sz %d, pad %d", ident,
     29 			sec->sec_image, sec->sec_size, sec->sec_pad);
     30 }
     31 
     32 #define ERRX(arg)		xerrx arg
     33 
     34 #else
     35 #define DPRINT_SEC(ident, sec)	/**/
     36 #define ERRX(arg)		return 1
     37 #endif
     38 
     39 /*
     40  * This code is size-hacked version of
     41  *
     42  *	sec->sec_image = (image);
     43  *	sec->sec_size = (size);
     44  *	sec->sec_pad = (pad);
     45  *	DPRINT_SEC((ident), sec);
     46  *	sec++;
     47  */
     48 #define SECTION(sec, ident, image, size, pad)	\
     49 	do {					\
     50 		u_long *wp = (void *) sec;	\
     51 		*(void **)wp++ = (image);	\
     52 		*wp++ = (size);			\
     53 		*wp++ = (pad);			\
     54 		DPRINT_SEC((ident), sec);	\
     55 		sec = (void *) wp;		\
     56 	} while (0)
     57 
     58 #define SECTION_NOPAD(sec, ident, image, size)	\
     59 		SECTION(sec, (ident), (image), (size), 0)
     60 
     61 static inline void
     62 bzero4(void *ptr, size_t siz)
     63 {
     64 	u_long *p;
     65 	u_short s;
     66 
     67 	p = ptr;
     68 	s = siz >> 2;
     69 
     70 	while (s--)
     71 		*p++ = 0;
     72 }
     73 
     74 /*
     75  * fill in loading information from an a.out executable
     76  */
     77 static void
     78 xk_aout(struct execkern_arg *xarg, struct exec *hdr)
     79 {
     80 	unsigned u;
     81 	char *s;
     82 	struct execkern_section *sec;
     83 
     84 	xarg->entry_addr = hdr->a_entry;
     85 	sec = xarg->sec;
     86 
     87 	/* text section and padding between data section */
     88 	s = (void *) (hdr + 1);
     89 	SECTION(sec, "text", s, hdr->a_text, -hdr->a_text & (AOUT_LDPGSZ-1));
     90 
     91 	/* data and bss sections */
     92 	s += hdr->a_text;
     93 	SECTION(sec, "data/bss", s, hdr->a_data, hdr->a_bss);
     94 
     95 	/* size of symbol table */
     96 	SECTION_NOPAD(sec, "symtab size", &sec[1].sec_size, sizeof(u_long));
     97 
     98 	/* symbol table section */
     99 	s += hdr->a_data;
    100 	SECTION_NOPAD(sec, "symbol", s, u = hdr->a_syms);
    101 
    102 	/* string table section */
    103 	if (u) {
    104 #ifdef LOADBSD
    105 		if (opt_v)
    106 			xwarnx("symbol table found");
    107 #endif
    108 		s += u;
    109 		SECTION_NOPAD(sec, "string", s, *(u_long *) s);
    110 	}
    111 }
    112 
    113 /*
    114  * fill in loading information from an ELF executable
    115  */
    116 static void
    117 xk_elf(struct execkern_arg *xarg, Elf32_Ehdr *hdr)
    118 {
    119 	char *top = (void *) hdr;
    120 	struct execkern_section *sec;
    121 	Elf32_Phdr *ph;
    122 	Elf32_Shdr *sh, *sym, *str, *stab, *shstr;
    123 	const char *shstrtab, *shname;
    124 	unsigned u, dpos, pd;
    125 	const char *const shstrtab_new = SHSTRTAB_FAKE;
    126 
    127 	xarg->entry_addr = hdr->e_entry;
    128 
    129 	/*
    130 	 * text, data, bss
    131 	 */
    132 	ph = (void *) (top + hdr->e_phoff);
    133 	xarg->load_addr = ph->p_vaddr;
    134 
    135 	sec = xarg->sec;
    136 	sec->sec_image = top + ph->p_offset;
    137 	sec->sec_size = ph->p_filesz;
    138 
    139 	if (hdr->e_phnum != 1) {
    140 		sec->sec_pad = ph[1].p_vaddr - (ph->p_vaddr + ph->p_filesz);
    141 		DPRINT_SEC("program (text)", sec);
    142 		sec++;
    143 		ph++;
    144 		sec->sec_image = top + ph->p_offset;
    145 		sec->sec_size = ph->p_filesz;
    146 	}
    147 
    148 	sec->sec_pad = ph->p_memsz - ph->p_filesz;
    149 	DPRINT_SEC("program (data/bss)", sec);
    150 	sec++;
    151 
    152 	/*
    153 	 * symbol size
    154 	 */
    155 	xarg->elfsymsiz = 0;		/* no symbol */
    156 	SECTION_NOPAD(sec, "symtab size", &xarg->elfsymsiz, sizeof(int));
    157 
    158 	/*
    159 	 * ELF header
    160 	 */
    161 	xarg->ehdr = *hdr;
    162 	xarg->ehdr.e_shstrndx = 0;	/* .shstrtab will be the 1st section */
    163 	SECTION_NOPAD(sec, "ELF header", &xarg->ehdr, sizeof(Elf32_Ehdr));
    164 
    165 	sh = (void *) (top + hdr->e_shoff);		/* section header */
    166 	shstr = sh + hdr->e_shstrndx;			/* .shstrtab */
    167 	shstrtab = top + shstr->sh_offset;
    168 
    169 	sym = str = stab = 0;
    170 	for (u = 0; sh++, ++u < hdr->e_shnum; ) {
    171 		shname = shstrtab + sh->sh_name;
    172 		if (!strcmp(shname, shstrtab_new + SHNAME_OFF_SYMTAB))
    173 			sym = sh;				/* .symtab */
    174 		if (!strcmp(shname, shstrtab_new + SHNAME_OFF_STRTAB))
    175 			str = sh;				/* .strtab */
    176 		if (!strcmp(shname, shstrtab_new + SHNAME_OFF_STAB))
    177 			stab = sh;				/* .stab */
    178 	}
    179 
    180 	if (shstr == 0 || sym == 0 || str == 0)
    181 		xarg->ehdr.e_shnum = 0;		/* no symbol */
    182 	else {
    183 #ifdef LOADBSD
    184 		if (opt_v) {
    185 			xwarnx("symbol table found");
    186 			if (stab)
    187 				xwarnx("debugging information found");
    188 		}
    189 #endif
    190 		xarg->elfsymsiz = 1;		/* has symbol */
    191 		xarg->ehdr.e_shnum = 3;
    192 		xarg->ehdr.e_shoff = sizeof(Elf32_Ehdr);
    193 
    194 		SECTION_NOPAD(sec, "section header (shstrtab)",
    195 				shstr, sizeof(Elf32_Shdr));
    196 
    197 		SECTION_NOPAD(sec, "section header (symbol)",
    198 				sym, sizeof(Elf32_Shdr));
    199 
    200 		SECTION_NOPAD(sec, "section header (string)",
    201 				str, sizeof(Elf32_Shdr));
    202 
    203 		dpos = sizeof(Elf32_Ehdr) + sizeof(Elf32_Shdr) * 3;
    204 		u = SIZE_SHSTRTAB_FAKE;
    205 
    206 		if (stab) {
    207 			xarg->ehdr.e_shnum++;
    208 			SECTION_NOPAD(sec, "section header (stab)",
    209 					stab, sizeof(Elf32_Shdr));
    210 			dpos += sizeof(Elf32_Shdr);
    211 			u = SIZE_SHSTRTAB_FAKE_WITH_STAB;
    212 		}
    213 
    214 		/* new .shstrtab section */
    215 		memcpy(xarg->shstrtab_fake, shstrtab_new, u);
    216 		/*
    217 		 * DDB requires symtab be aligned.
    218 		 */
    219 		pd = -u & ALIGNBYTES;
    220 		SECTION(sec, "shstrtab", &xarg->shstrtab_fake, u, pd);
    221 		shstr->sh_name = SHNAME_OFF_SHSTRTAB;
    222 		shstr->sh_offset = dpos;
    223 		dpos += u + pd;
    224 
    225 		SECTION_NOPAD(sec, "symtab",
    226 				top + sym->sh_offset, sym->sh_size);
    227 		sym->sh_name = SHNAME_OFF_SYMTAB;
    228 		sym->sh_offset = dpos;
    229 		dpos += sym->sh_size;
    230 
    231 		SECTION_NOPAD(sec, "strtab",
    232 				top + str->sh_offset, str->sh_size);
    233 		str->sh_name = SHNAME_OFF_STRTAB;
    234 		str->sh_offset = dpos;
    235 		dpos += str->sh_size;
    236 
    237 		if (stab) {
    238 			SECTION_NOPAD(sec, "stab",
    239 					top + stab->sh_offset, stab->sh_size);
    240 			stab->sh_name = SHNAME_OFF_STAB;
    241 			stab->sh_offset = dpos;
    242 		}
    243 	}
    244 }
    245 
    246 
    247 int
    248 xk_load(struct execkern_arg *xarg, void *buf, u_long loadaddr)
    249 	/* loadaddr:	 for a.out */
    250 {
    251 	struct exec *ahdr;
    252 	Elf32_Ehdr *ehdr;
    253 	unsigned u;
    254 
    255 	/* Unused section entries should be cleared to zero. */
    256 	bzero4(xarg->sec, sizeof xarg->sec);
    257 
    258 	xarg->load_addr = loadaddr;
    259 
    260 	/*
    261 	 * check exec header
    262 	 */
    263 	ahdr = buf;
    264 	ehdr = buf;
    265 
    266 	if (N_GETMAGIC(*ahdr) == NMAGIC) {
    267 		/*
    268 		 * this is an a.out
    269 		 */
    270 #ifdef LOADBSD
    271 		if (opt_v)
    272 			xwarnx("%s: is an a.out", kernel_fn);
    273 #endif
    274 #ifdef BOOT
    275 B_PRINT("This is an a.out\r\n");
    276 #endif
    277 
    278 		if ((u = N_GETMID(*ahdr)) != MID_M68K)
    279 			ERRX((1, "%s: Wrong architecture (mid %u)",
    280 					kernel_fn, u));
    281 
    282 		/*
    283 		 * fill in loading information
    284 		 */
    285 		xk_aout(xarg, ahdr);
    286 
    287 	} else {
    288 
    289 		/*
    290 		 * check ELF header
    291 		 */
    292 		if (*(u_int32_t *)&ehdr->e_ident[EI_MAG0] !=
    293 			(ELFMAG0<<24 | ELFMAG1<<16 | ELFMAG2<<8 | ELFMAG3) ||
    294 		    *(u_int16_t *)&ehdr->e_ident[EI_CLASS] !=
    295 			(ELFCLASS32 << 8 | ELFDATA2MSB))
    296 			ERRX((1, "%s: Not an NMAGIC a.out or a 32bit BE ELF",
    297 					kernel_fn));
    298 
    299 		/*
    300 		 * this is an ELF
    301 		 */
    302 #ifdef LOADBSD
    303 		if (opt_v)
    304 			xwarnx("%s: is an ELF", kernel_fn);
    305 #endif
    306 #ifdef BOOT
    307 B_PRINT("This is an ELF\r\n");
    308 #endif
    309 
    310 		if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
    311 		    ehdr->e_version != EV_CURRENT)
    312 			ERRX((1, "%s: Unsupported ELF version", kernel_fn));
    313 
    314 		if ((u = ehdr->e_machine) != EM_68K)
    315 			ERRX((1, "%s: Wrong architecture (mid %u)",
    316 					kernel_fn, u));
    317 		if (ehdr->e_type != ET_EXEC)
    318 			ERRX((1, "%s: Not an executable", kernel_fn));
    319 		if ((u = ehdr->e_phnum) != 1 && u != 2)
    320 			ERRX((1, "%s: Wrong number (%u) of loading sections",
    321 					kernel_fn, u));
    322 
    323 		/*
    324 		 * fill in loading information
    325 		 */
    326 		xk_elf(xarg, ehdr);
    327 	}
    328 
    329 	return 0;
    330 }
    331