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