1 /* $NetBSD: coff_exec.c,v 1.36 2024/09/08 09:36:49 rillig Exp $ */ 2 3 /* 4 * Copyright (c) 1994, 1995 Scott Bartram 5 * Copyright (c) 1994 Adam Glass 6 * Copyright (c) 1993, 1994 Christopher G. Demetriou 7 * All rights reserved. 8 * 9 * originally from kern/exec_ecoff.c 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by Scott Bartram. 22 * 4. The name of the author may not be used to endorse or promote products 23 * derived from this software without specific prior written permission 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: coff_exec.c,v 1.36 2024/09/08 09:36:49 rillig Exp $"); 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/proc.h> 43 #include <sys/exec.h> 44 #include <sys/vnode.h> 45 #include <sys/resourcevar.h> 46 #include <sys/namei.h> 47 #include <sys/exec_coff.h> 48 #include <sys/module.h> 49 50 #include <uvm/uvm_extern.h> 51 52 MODULE(MODULE_CLASS_MISC, exec_coff, NULL); 53 54 static int coff_find_section(struct lwp *, struct vnode *, 55 struct coff_filehdr *, struct coff_scnhdr *, int); 56 57 static struct execsw exec_coff_execsw[] = { 58 { COFF_HDR_SIZE, 59 exec_coff_makecmds, 60 { NULL }, 61 &emul_netbsd, 62 EXECSW_PRIO_ANY, 63 0, 64 copyargs, 65 NULL, 66 coredump_netbsd, 67 exec_setup_stack }, 68 }; 69 70 static int 71 exec_coff_modcmd(modcmd_t cmd, void *arg) 72 { 73 74 switch (cmd) { 75 case MODULE_CMD_INIT: 76 return exec_add(exec_coff_execsw, 77 __arraycount(exec_coff_execsw)); 78 79 case MODULE_CMD_FINI: 80 return exec_remove(exec_coff_execsw, 81 __arraycount(exec_coff_execsw)); 82 83 default: 84 return ENOTTY; 85 } 86 } 87 88 /* 89 * exec_coff_makecmds(): Check if it's a coff-format executable. 90 * 91 * Given a lwp pointer and an exec package pointer, see if the referent 92 * of the epp is in coff format. Check 'standard' magic numbers for 93 * this architecture. If that fails, return failure. 94 * 95 * This function is responsible for creating a set of vmcmds which can be 96 * used to build the process's vm space and inserting them into the exec 97 * package. 98 */ 99 100 int 101 exec_coff_makecmds(struct lwp *l, struct exec_package *epp) 102 { 103 int error; 104 struct coff_filehdr *fp = epp->ep_hdr; 105 struct coff_aouthdr *ap; 106 107 if (epp->ep_hdrvalid < COFF_HDR_SIZE) 108 return ENOEXEC; 109 110 if (COFF_BADMAG(fp)) 111 return ENOEXEC; 112 113 ap = (void *)((char *)epp->ep_hdr + sizeof(struct coff_filehdr)); 114 switch (ap->a_magic) { 115 case COFF_OMAGIC: 116 error = exec_coff_prep_omagic(l, epp, fp, ap); 117 break; 118 case COFF_NMAGIC: 119 error = exec_coff_prep_nmagic(l, epp, fp, ap); 120 break; 121 case COFF_ZMAGIC: 122 error = exec_coff_prep_zmagic(l, epp, fp, ap); 123 break; 124 default: 125 return ENOEXEC; 126 } 127 128 #ifdef TODO 129 if (error == 0) 130 error = cpu_exec_coff_hook(p, epp); 131 #endif 132 133 if (error) 134 kill_vmcmds(&epp->ep_vmcmds); 135 136 return error; 137 } 138 139 /* 140 * exec_coff_prep_omagic(): Prepare a COFF OMAGIC binary's exec package 141 */ 142 143 int 144 exec_coff_prep_omagic(struct lwp *l, struct exec_package *epp, 145 struct coff_filehdr *fp, struct coff_aouthdr *ap) 146 { 147 epp->ep_taddr = COFF_SEGMENT_ALIGN(fp, ap, ap->a_tstart); 148 epp->ep_tsize = ap->a_tsize; 149 epp->ep_daddr = COFF_SEGMENT_ALIGN(fp, ap, ap->a_dstart); 150 epp->ep_dsize = ap->a_dsize; 151 epp->ep_entry = ap->a_entry; 152 153 /* set up command for text and data segments */ 154 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 155 ap->a_tsize + ap->a_dsize, epp->ep_taddr, epp->ep_vp, 156 COFF_TXTOFF(fp, ap), 157 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 158 159 /* set up command for bss segment */ 160 #ifdef __sh__ 161 if (ap->a_bsize > 0) 162 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, ap->a_bsize, 163 COFF_ROUND(ap->a_dstart + ap->a_dsize, COFF_LDPGSZ), 164 NULLVP, 0, 165 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 166 #else 167 if (ap->a_bsize > 0) 168 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, ap->a_bsize, 169 COFF_SEGMENT_ALIGN(fp, ap, 170 ap->a_dstart + ap->a_dsize), 171 NULLVP, 0, 172 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 173 #endif 174 175 return (*epp->ep_esch->es_setup_stack)(l, epp); 176 } 177 178 /* 179 * exec_coff_prep_nmagic(): Prepare a 'native' NMAGIC COFF binary's exec 180 * package. 181 */ 182 183 int 184 exec_coff_prep_nmagic(struct lwp *l, struct exec_package *epp, struct coff_filehdr *fp, struct coff_aouthdr *ap) 185 { 186 epp->ep_taddr = COFF_SEGMENT_ALIGN(fp, ap, ap->a_tstart); 187 epp->ep_tsize = ap->a_tsize; 188 epp->ep_daddr = COFF_ROUND(ap->a_dstart, COFF_LDPGSZ); 189 epp->ep_dsize = ap->a_dsize; 190 epp->ep_entry = ap->a_entry; 191 192 /* set up command for text segment */ 193 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, epp->ep_tsize, 194 epp->ep_taddr, epp->ep_vp, COFF_TXTOFF(fp, ap), 195 VM_PROT_READ|VM_PROT_EXECUTE); 196 197 /* set up command for data segment */ 198 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, epp->ep_dsize, 199 epp->ep_daddr, epp->ep_vp, COFF_DATOFF(fp, ap), 200 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 201 202 /* set up command for bss segment */ 203 if (ap->a_bsize > 0) 204 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, ap->a_bsize, 205 COFF_SEGMENT_ALIGN(fp, ap, 206 ap->a_dstart + ap->a_dsize), 207 NULLVP, 0, 208 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 209 210 return (*epp->ep_esch->es_setup_stack)(l, epp); 211 } 212 213 /* 214 * coff_find_section - load specified section header 215 * 216 * TODO - optimize by reading all section headers in at once 217 */ 218 219 static int 220 coff_find_section(struct lwp *l, struct vnode *vp, struct coff_filehdr *fp, 221 struct coff_scnhdr *sh, int s_type) 222 { 223 int i, pos, error; 224 size_t siz, resid; 225 226 pos = COFF_HDR_SIZE; 227 for (i = 0; i < fp->f_nscns; i++, pos += sizeof(struct coff_scnhdr)) { 228 siz = sizeof(struct coff_scnhdr); 229 error = vn_rdwr(UIO_READ, vp, (void *) sh, 230 siz, pos, UIO_SYSSPACE, IO_NODELOCKED, l->l_cred, 231 &resid, NULL); 232 if (error) { 233 DPRINTF(("section hdr %d read error %d\n", i, error)); 234 return error; 235 } 236 siz -= resid; 237 if (siz != sizeof(struct coff_scnhdr)) { 238 DPRINTF(("incomplete read: hdr %d ask=%d, rem=%zu got %zu\n", 239 s_type, sizeof(struct coff_scnhdr), 240 resid, siz)); 241 return ENOEXEC; 242 } 243 DPRINTF(("found section: %lu\n", sh->s_flags)); 244 if (sh->s_flags == s_type) 245 return 0; 246 } 247 return ENOEXEC; 248 } 249 250 /* 251 * exec_coff_prep_zmagic(): Prepare a COFF ZMAGIC binary's exec package 252 * 253 * First, set the various offsets/lengths in the exec package. 254 * 255 * Then, mark the text image busy (so it can be demand paged) or error 256 * out if this is not possible. Finally, set up vmcmds for the 257 * text, data, bss, and stack segments. 258 */ 259 260 int 261 exec_coff_prep_zmagic(struct lwp *l, struct exec_package *epp, 262 struct coff_filehdr *fp, struct coff_aouthdr *ap) 263 { 264 int error; 265 u_long offset; 266 long dsize; 267 #ifndef __sh__ 268 long baddr, bsize; 269 #endif 270 struct coff_scnhdr sh; 271 272 DPRINTF(("enter exec_coff_prep_zmagic\n")); 273 274 /* set up command for text segment */ 275 error = coff_find_section(l, epp->ep_vp, fp, &sh, COFF_STYP_TEXT); 276 if (error) { 277 DPRINTF(("can't find text section: %d\n", error)); 278 return error; 279 } 280 DPRINTF(("COFF text addr %lu size %ld offset %ld\n", sh.s_vaddr, 281 sh.s_size, sh.s_scnptr)); 282 epp->ep_taddr = COFF_ALIGN(sh.s_vaddr); 283 offset = sh.s_scnptr - (sh.s_vaddr - epp->ep_taddr); 284 epp->ep_tsize = sh.s_size + (sh.s_vaddr - epp->ep_taddr); 285 286 error = vn_marktext(epp->ep_vp); 287 if (error) 288 return (error); 289 290 DPRINTF(("VMCMD: addr %lx size %lx offset %lx\n", epp->ep_taddr, 291 epp->ep_tsize, offset)); 292 if (!(offset & PAGE_MASK) && !(epp->ep_taddr & PAGE_MASK)) { 293 epp->ep_tsize = round_page(epp->ep_tsize); 294 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, epp->ep_tsize, 295 epp->ep_taddr, epp->ep_vp, offset, 296 VM_PROT_READ|VM_PROT_EXECUTE); 297 } else { 298 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, epp->ep_tsize, 299 epp->ep_taddr, epp->ep_vp, offset, 300 VM_PROT_READ|VM_PROT_EXECUTE); 301 } 302 303 /* set up command for data segment */ 304 error = coff_find_section(l, epp->ep_vp, fp, &sh, COFF_STYP_DATA); 305 if (error) { 306 DPRINTF(("can't find data section: %d\n", error)); 307 return error; 308 } 309 DPRINTF(("COFF data addr %lx size %ld offset %ld\n", sh.s_vaddr, 310 sh.s_size, sh.s_scnptr)); 311 epp->ep_daddr = COFF_ALIGN(sh.s_vaddr); 312 offset = sh.s_scnptr - (sh.s_vaddr - epp->ep_daddr); 313 dsize = sh.s_size + (sh.s_vaddr - epp->ep_daddr); 314 #ifdef __sh__ 315 epp->ep_dsize = round_page(dsize) + ap->a_bsize; 316 #else 317 epp->ep_dsize = dsize + ap->a_bsize; 318 #endif 319 320 DPRINTF(("VMCMD: addr %lx size %lx offset %lx\n", epp->ep_daddr, 321 dsize, offset)); 322 if (!(offset & PAGE_MASK) && !(epp->ep_daddr & PAGE_MASK)) { 323 dsize = round_page(dsize); 324 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_pagedvn, dsize, 325 epp->ep_daddr, epp->ep_vp, offset, 326 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 327 } else { 328 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 329 dsize, epp->ep_daddr, epp->ep_vp, offset, 330 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 331 } 332 333 #ifdef __sh__ 334 if (ap->a_bsize > 0) { 335 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, ap->a_bsize, 336 COFF_ROUND(ap->a_dstart + ap->a_dsize, COFF_LDPGSZ), 337 NULLVP, 0, 338 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 339 } 340 #else 341 /* set up command for bss segment */ 342 baddr = round_page(epp->ep_daddr + dsize); 343 bsize = epp->ep_daddr + epp->ep_dsize - baddr; 344 if (bsize > 0) { 345 DPRINTF(("VMCMD: addr %x size %x offset %x\n", 346 baddr, bsize, 0)); 347 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, 348 bsize, baddr, NULLVP, 0, 349 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 350 } 351 #endif 352 353 #ifdef TODO 354 /* load any shared libraries */ 355 error = coff_find_section(l, epp->ep_vp, fp, &sh, COFF_STYP_SHLIB); 356 if (!error) { 357 size_t resid; 358 struct coff_slhdr *slhdr; 359 char buf[128], *bufp; /* FIXME */ 360 int len = sh.s_size, path_index, entry_len; 361 362 DPRINTF(("COFF shlib size %d offset %d\n", 363 sh.s_size, sh.s_scnptr)); 364 365 error = vn_rdwr(UIO_READ, epp->ep_vp, (void *) buf, 366 len, sh.s_scnptr, 367 UIO_SYSSPACE, IO_NODELOCKED, l->l_cred, 368 &resid, NULL); 369 if (error) { 370 DPRINTF(("shlib section read error %d\n", error)); 371 return ENOEXEC; 372 } 373 bufp = buf; 374 while (len) { 375 slhdr = (struct coff_slhdr *)bufp; 376 path_index = slhdr->path_index * sizeof(long); 377 entry_len = slhdr->entry_len * sizeof(long); 378 379 DPRINTF(("path_index: %d entry_len: %d name: %s\n", 380 path_index, entry_len, slhdr->sl_name)); 381 382 error = coff_load_shlib(p, slhdr->sl_name, epp); 383 if (error) 384 return ENOEXEC; 385 bufp += entry_len; 386 len -= entry_len; 387 } 388 } 389 #endif 390 /* set up entry point */ 391 epp->ep_entry = ap->a_entry; 392 393 #if 1 394 DPRINTF(("text addr: %lx size: %ld data addr: %lx size: %ld entry: %lx\n", 395 epp->ep_taddr, epp->ep_tsize, 396 epp->ep_daddr, epp->ep_dsize, 397 epp->ep_entry)); 398 #endif 399 return (*epp->ep_esch->es_setup_stack)(l, epp); 400 } 401 402 #if 0 403 int 404 coff_load_shlib(struct lwp *l, char *path, struct exec_package *epp) 405 { 406 int error; 407 size_t siz, resid; 408 int taddr, tsize, daddr, dsize, offset; 409 struct vnode *vp; 410 struct coff_filehdr fh, *fhp = &fh; 411 struct coff_scnhdr sh, *shp = &sh; 412 413 /* 414 * 1. open shlib file 415 * 2. read filehdr 416 * 3. map text, data, and bss out of it using VM_* 417 */ 418 /* first get the vnode */ 419 error = namei_simple_kernel(path, NSM_FOLLOW_TRYEMULROOT, &vp); 420 if (error != 0) { 421 DPRINTF(("coff_load_shlib: can't find library %s\n", path)); 422 return error; 423 } 424 425 siz = sizeof(struct coff_filehdr); 426 error = vn_rdwr(UIO_READ, vp, (void *) fhp, siz, 0, 427 UIO_SYSSPACE, IO_NODELOCKED, l->l_cred, &resid, NULL); 428 if (error) { 429 DPRINTF(("filehdr read error %d\n", error)); 430 vrele(vp); 431 return error; 432 } 433 siz -= resid; 434 if (siz != sizeof(struct coff_filehdr)) { 435 DPRINTF(("coff_load_shlib: incomplete read: ask=%d, rem=%zu got %zu\n", 436 sizeof(struct coff_filehdr), resid, siz)); 437 vrele(vp); 438 return ENOEXEC; 439 } 440 441 /* load text */ 442 error = coff_find_section(l, vp, fhp, shp, COFF_STYP_TEXT); 443 if (error) { 444 DPRINTF(("can't find shlib text section\n")); 445 vrele(vp); 446 return error; 447 } 448 DPRINTF(("COFF text addr %x size %d offset %d\n", sh.s_vaddr, 449 sh.s_size, sh.s_scnptr)); 450 taddr = COFF_ALIGN(shp->s_vaddr); 451 offset = shp->s_scnptr - (shp->s_vaddr - taddr); 452 tsize = shp->s_size + (shp->s_vaddr - taddr); 453 DPRINTF(("VMCMD: addr %x size %x offset %x\n", taddr, tsize, offset)); 454 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, tsize, taddr, 455 vp, offset, 456 VM_PROT_READ|VM_PROT_EXECUTE); 457 458 /* load data */ 459 error = coff_find_section(l, vp, fhp, shp, COFF_STYP_DATA); 460 if (error) { 461 DPRINTF(("can't find shlib data section\n")); 462 vrele(vp); 463 return error; 464 } 465 DPRINTF(("COFF data addr %x size %d offset %d\n", shp->s_vaddr, 466 shp->s_size, shp->s_scnptr)); 467 daddr = COFF_ALIGN(shp->s_vaddr); 468 offset = shp->s_scnptr - (shp->s_vaddr - daddr); 469 dsize = shp->s_size + (shp->s_vaddr - daddr); 470 /* epp->ep_dsize = dsize + ap->a_bsize; */ 471 472 DPRINTF(("VMCMD: addr %x size %x offset %x\n", daddr, dsize, offset)); 473 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_readvn, 474 dsize, daddr, vp, offset, 475 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 476 477 /* load bss */ 478 error = coff_find_section(l, vp, fhp, shp, COFF_STYP_BSS); 479 if (!error) { 480 int baddr = round_page(daddr + dsize); 481 int bsize = daddr + dsize + shp->s_size - baddr; 482 if (bsize > 0) { 483 DPRINTF(("VMCMD: addr %x size %x offset %x\n", 484 baddr, bsize, 0)); 485 NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, 486 bsize, baddr, NULLVP, 0, 487 VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE); 488 } 489 } 490 vrele(vp); 491 492 return 0; 493 } 494 #endif 495 496