Files
Arquivotheca.Solaris-2.5/uts/common/exec/aout/aout.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

442 lines
10 KiB
C
Executable File

/*
* Copyright (c) 1990 by Sun Microsystems, Inc.
*/
#ident "@(#)aout.c 1.41 95/02/28 SMI"
/*
* a.out exec module.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/fpu/fpusystm.h>
#include <sys/sysmacros.h>
#include <sys/signal.h>
#include <sys/cred.h>
#include <sys/user.h>
#include <sys/errno.h>
#include <sys/vnode.h>
#include <sys/mman.h>
#include <sys/kmem.h>
#include <sys/proc.h>
#include <sys/pathname.h>
#include <sys/cmn_err.h>
#include <sys/debug.h>
#include <sys/exec.h>
#include <sys/exechdr.h>
#include <sys/auxv.h>
#include <sys/core.h>
#include <sys/procfs.h>
#include <sys/vmparam.h>
#include <sys/archsystm.h>
#include <vm/anon.h>
#include <vm/as.h>
#include <vm/seg.h>
/*
* Size of u-area.
*/
#define USIZE 4*4096
/*
* This is the loadable module wrapper.
*/
#include <sys/modctl.h>
static int aoutexec(struct vnode *vp, struct execa *uap, struct uarg *args,
struct intpdata *idatap, int level, long *execsz, int setid,
caddr_t exec_file, struct cred *cred);
static int get_aout_head(struct vnode **vpp, struct exdata *edp, long *execsz,
int *isdyn);
static int aoutcore(vnode_t *vp, proc_t *pp, struct cred *credp,
rlim_t rlimit, int sig);
extern int elfexec();
extern int at_flags;
char _depends_on[] = "exec/elfexec";
static struct execsw nesw = {
&aout_nmagic,
aoutexec,
aoutcore
};
static struct execsw zesw = {
&aout_zmagic,
aoutexec,
aoutcore
};
static struct execsw oesw = {
&aout_omagic,
aoutexec,
aoutcore
};
/*
* Module linkage information for the kernel.
*/
static struct modlexec nexec = {
&mod_execops, "exec for NMAGIC", &nesw
};
static struct modlexec zexec = {
&mod_execops, "exec for ZMAGIC", &zesw
};
static struct modlexec oexec = {
&mod_execops, "exec for OMAGIC", &oesw
};
static struct modlinkage modlinkage = {
MODREV_1, (void *)&nexec, (void *)&zexec, (void *)&oexec, NULL
};
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
_fini(void)
{
return (mod_remove(&modlinkage));
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
/*ARGSUSED*/
static int
aoutexec(
struct vnode *vp,
struct execa *uap,
struct uarg *args,
struct intpdata *idatap,
int level,
long *execsz,
int setid,
caddr_t exec_file,
struct cred *cred)
{
register int error;
struct exdata edp, edpout;
struct execenv exenv;
register proc_t *pp = ttoproc(curthread);
struct vnode *nvp;
int pagetext, pagedata;
int dataprot = PROT_ALL;
int textprot = PROT_ALL & ~PROT_WRITE;
int isdyn;
auxv_t auxv[NUM_AUX_VECTORS];
int *aux;
struct user *up = PTOU(pp);
/*
* Read in and validate the file header.
*/
if (error = get_aout_head(&vp, &edp, execsz, &isdyn)) {
return (error);
}
if (error = chkaout(&edp)) {
return (error);
}
/*
* Take a quick look to see if it looks like we will have
* enough swap space for the program to get started. This
* is not a guarantee that we will succeed, but it is definitely
* better than finding this out after we are committed to the
* new memory image. Maybe what is needed is a way to "prereserve"
* swap space for some segment mappings here.
*
* But with shared libraries the process can make it through
* the exec only to have ld.so fail to get the program going
* because its mmap's will not be able to succeed if the system
* is running low on swap space. In fact this is a far more
* common failure mode, but we cannot do much about this here
* other than add some slop to our anonymous memory resources
* requirements estimate based on some guess since we cannot know
* what else the program will really need to get to a useful state.
*
* XXX - The stack size (clrnd(SSIZE + btoc(nargc))) should also
* be used when checking for swap space. This requires some work
* since nargc is actually determined in exec_args() which is done
* after this check and hence we punt for now.
*
* nargc = SA(nc + (na + 4) * NBPW) + sizeof (struct rwindow);
*/
if (anoninfo.ani_max - anoninfo.ani_resv <
btoc(edp.ux_dsize) + btoc(SSIZE)) {
return (ENOMEM);
}
if (enable_mixed_bcp)
isdyn = 0;
if (isdyn) {
/*
* Build a small aux vector
*/
aux = (int *)auxv;
*aux++ = AT_PAGESZ;
*aux++ = PAGESIZE;
*aux++ = AT_FLAGS;
*aux++ = at_flags;
/*
* Save uid, ruid, gid and rgid information
* for the linker.
*/
*aux++ = AT_SUN_UID;
*aux++ = cred->cr_uid;
*aux++ = AT_SUN_RUID;
*aux++ = cred->cr_ruid;
*aux++ = AT_SUN_GID;
*aux++ = cred->cr_gid;
*aux++ = AT_SUN_RGID;
*aux++ = cred->cr_rgid;
/*
* Hardware capability flag word (performance hints)
*/
*aux++ = AT_SUN_HWCAP;
*aux++ = auxv_hwcap;
*aux++ = AT_NULL;
*aux = 0;
args->auxsize = 8 * sizeof (auxv_t);
/*
* Move args to user's stack and destroy the old
* user address space.
*/
if (error = exec_args(uap, args, idatap, (int **)NULL)) {
if (error == -1) {
error = ENOEXEC;
goto done;
}
return (error);
}
/*
* Wedge the aux vector on the end of the environment
*/
bzero((caddr_t)up->u_auxv, sizeof (up->u_auxv));
error = execpoststack(args, auxv, args->auxsize);
if (error != 0)
goto done;
ASSERT(args->auxsize <= sizeof (up->u_auxv));
bcopy((caddr_t)auxv, (caddr_t)up->u_auxv, args->auxsize);
} else {
/*
* Load the trap 0 interpreter.
*/
if (error = lookupname("/usr/4lib/sbcp", UIO_SYSSPACE, FOLLOW,
NULLVPP, &nvp)) {
goto done;
}
if (error = elfexec(nvp, uap, args, idatap, level, execsz,
setid, exec_file, cred)) {
VN_RELE(nvp);
return (error);
}
VN_RELE(nvp);
}
/*
* Determine the a.out's characteristics.
*/
getexinfo(&edp, &edpout, &pagetext, &pagedata);
/*
* Load the a.out's text and data.
*/
if (error = execmap(edp.vp, edp.ux_txtorg, edp.ux_tsize,
(size_t)0, edp.ux_toffset, textprot, pagetext))
goto done;
if (error = execmap(edp.vp, edp.ux_datorg, edp.ux_dsize,
edp.ux_bsize, edp.ux_doffset, dataprot, pagedata))
goto done;
exenv.ex_brkbase = (caddr_t)edp.ux_datorg;
exenv.ex_brksize = edp.ux_dsize + edp.ux_bsize;
exenv.ex_magic = edp.ux_mag;
exenv.ex_vp = edp.vp;
setexecenv(&exenv);
if (isdyn)
u.u_exdata = edp;
done:
if (error != 0)
psignal(pp, SIGKILL);
return (error);
}
/*
* Read in and validate the file header.
*/
static int
get_aout_head(vpp, edp, execsz, isdyn)
struct vnode **vpp;
struct exdata *edp;
long *execsz;
int *isdyn;
{
struct vnode *vp = *vpp;
struct exec filhdr;
int error, resid;
if (error = vn_rdwr(UIO_READ, vp, (caddr_t)&filhdr,
(int)sizeof (filhdr), (off_t)0, UIO_SYSSPACE, 0,
(long)0, CRED(), &resid))
return (error);
if (resid != 0)
return (ENOEXEC);
switch (filhdr.a_magic) {
case OMAGIC:
filhdr.a_data += filhdr.a_text;
filhdr.a_text = 0;
break;
case ZMAGIC:
case NMAGIC:
break;
default:
return (ENOEXEC);
}
/*
* Check total memory requirements (in clicks) for a new process
* against the available memory or upper limit of memory allowed.
*/
*execsz += btoc(filhdr.a_text + filhdr.a_data);
if (*execsz > btoc(u.u_rlimit[RLIMIT_VMEM].rlim_cur))
return (ENOMEM);
edp->ux_mach = filhdr.a_machtype;
edp->ux_tsize = filhdr.a_text;
edp->ux_dsize = filhdr.a_data;
edp->ux_bsize = filhdr.a_bss;
edp->ux_mag = filhdr.a_magic;
edp->ux_toffset = gettfile(&filhdr);
edp->ux_doffset = getdfile(&filhdr);
edp->ux_txtorg = gettmem(&filhdr);
edp->ux_datorg = getdmem(&filhdr);
edp->ux_entloc = (caddr_t)filhdr.a_entry;
edp->vp = vp;
*isdyn = filhdr.a_dynamic;
return (0);
}
/*
* Create a core image on the file "core". Writes a struct core
* followed by the entire data+stack segments and user area.
*/
static int
aoutcore(vp, pp, credp, rlimit, sig)
vnode_t *vp;
proc_t *pp;
struct cred *credp;
rlim_t rlimit;
int sig;
{
struct core *corep;
struct user *up = PTOU(pp);
off_t offset = 0;
caddr_t base;
int count, error, len;
klwp_id_t lwp = ttolwp(curthread);
extern void getgregs();
ASSERT(pp == curproc);
up->u_tsize = btoc(up->u_exdata.ux_tsize);
up->u_dsize = btoc(up->u_exdata.ux_dsize +
up->u_exdata.ux_bsize + pp->p_brksize);
/*
* Dump the specific areas of the u area into the new
* core structure for examination by debuggers. The
* new format is now independent of the user structure and
* only the information needed by the debuggers is included.
*/
corep = (struct core *)kmem_zalloc(sizeof (struct core), KM_SLEEP);
corep->c_magic = CORE_MAGIC;
corep->c_len = sizeof (struct core);
getgregs(lwp, &corep->c_regs);
fp_core(corep);
corep->c_ucode = lwp->lwp_siginfo.si_code;
corep->c_exdata = up->u_exdata;
corep->c_signo = sig;
corep->c_tsize = ctob(up->u_tsize);
corep->c_dsize = ctob(up->u_dsize);
corep->c_ssize = pp->p_stksize;
len = min(MAXCOMLEN, CORE_NAMELEN);
(void) strncpy(corep->c_cmdname, up->u_comm, len);
corep->c_cmdname[len] = '\0';
/*
* Write out core file header.
*/
if (error = vn_rdwr(UIO_WRITE, vp, (caddr_t)corep,
(int)sizeof (struct core), (off_t)offset, UIO_SYSSPACE,
0, rlimit, credp, (int *)NULL)) {
kmem_free((void *)corep, sizeof (struct core));
return (error);
}
offset += sizeof (struct core);
kmem_free((void *)corep, sizeof (struct core));
/*
* Check the sizes against the current ulimit and
* don't write a file bigger than ulimit. If we
* can't write everything, we would prefer to
* write the stack and not the data rather than
* the other way around.
*/
if (ctob(sizeof (struct user) + up->u_dsize + pp->p_stksize) >
rlimit) {
up->u_dsize = 0;
if (ctob(sizeof (struct user) + pp->p_stksize) > rlimit)
pp->p_stksize = 0;
}
/*
* Write the data and stack to the dump file.
*/
if (up->u_dsize) {
base = (caddr_t)up->u_exdata.ux_datorg;
count = ctob(up->u_dsize) - PAGOFF(base);
if (error = core_seg(pp, vp, (int)offset, base, count,
rlimit, credp))
return (error);
offset += ctob(btoc(count));
}
if (pp->p_stksize) {
if (error = core_seg(pp, vp, (int)offset,
(caddr_t)(USRSTACK - pp->p_stksize),
(int)pp->p_stksize, rlimit, credp))
return (error);
offset += pp->p_stksize;
}
/*
* Write the u-area (for those who care).
*/
if (error = vn_rdwr(UIO_WRITE, vp, (caddr_t)up, USIZE,
offset, UIO_SYSSPACE, 0, rlimit, credp, (int *)NULL))
return (error);
return (error);
}