add a linux_rt_sigframe to support SA_SIGINFO, and use it when SA_SIGINFO

is requested. This appears to be how linuxthreads decides which signal handler
to use.
This commit is contained in:
christos 2002-12-06 00:02:59 +00:00
parent c363ae66f1
commit ef042d8e23
2 changed files with 203 additions and 55 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_machdep.c,v 1.82 2002/11/26 18:42:38 christos Exp $ */
/* $NetBSD: linux_machdep.c,v 1.83 2002/12/06 00:02:59 christos Exp $ */
/*-
* Copyright (c) 1995, 2000 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.82 2002/11/26 18:42:38 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.83 2002/12/06 00:02:59 christos Exp $");
#if defined(_KERNEL_OPT)
#include "opt_vm86.h"
@ -119,7 +119,12 @@ int linux_write_ldt __P((struct proc *, struct linux_sys_modify_ldt_args *,
static struct biosdisk_info *fd2biosinfo __P((struct proc *, struct file *));
extern struct disklist *i386_alldisks;
static void linux_savecontext __P((struct proc *, struct trapframe *,
sigset_t *, struct linux_sigcontext *));
static void linux_rt_sendsig __P((int, sigset_t *, u_long));
static void linux_old_sendsig __P((int, sigset_t *, u_long));
extern char linux_sigcode[], linux_rt_sigcode[];
/*
* Deal with some i386-specific things in the Linux emulation code.
*/
@ -186,6 +191,140 @@ linux_sendsig(sig, mask, code)
int sig;
sigset_t *mask;
u_long code;
{
if (SIGACTION(curproc, sig).sa_flags & SA_SIGINFO)
linux_rt_sendsig(sig, mask, code);
else
linux_old_sendsig(sig, mask, code);
}
static void
linux_savecontext(p, tf, mask, sc)
struct proc *p;
struct trapframe *tf;
sigset_t *mask;
struct linux_sigcontext *sc;
{
/* Save register context. */
#ifdef VM86
if (tf->tf_eflags & PSL_VM) {
sc->sc_gs = tf->tf_vm86_gs;
sc->sc_fs = tf->tf_vm86_fs;
sc->sc_es = tf->tf_vm86_es;
sc->sc_ds = tf->tf_vm86_ds;
sc->sc_eflags = get_vflags(p);
} else
#endif
{
sc->sc_gs = tf->tf_gs;
sc->sc_fs = tf->tf_fs;
sc->sc_es = tf->tf_es;
sc->sc_ds = tf->tf_ds;
sc->sc_eflags = tf->tf_eflags;
}
sc->sc_edi = tf->tf_edi;
sc->sc_esi = tf->tf_esi;
sc->sc_esp = tf->tf_esp;
sc->sc_ebp = tf->tf_ebp;
sc->sc_ebx = tf->tf_ebx;
sc->sc_edx = tf->tf_edx;
sc->sc_ecx = tf->tf_ecx;
sc->sc_eax = tf->tf_eax;
sc->sc_eip = tf->tf_eip;
sc->sc_cs = tf->tf_cs;
sc->sc_esp_at_signal = tf->tf_esp;
sc->sc_ss = tf->tf_ss;
sc->sc_err = tf->tf_err;
sc->sc_trapno = tf->tf_trapno;
sc->sc_cr2 = p->p_addr->u_pcb.pcb_cr2;
sc->sc_387 = NULL;
/* Save signal stack. */
/* Linux doesn't save the onstack flag in sigframe */
/* Save signal mask. */
native_to_linux_old_sigset(&sc->sc_mask, mask);
}
static void
linux_rt_sendsig(sig, mask, code)
int sig;
sigset_t *mask;
u_long code;
{
struct proc *p = curproc;
struct trapframe *tf;
struct linux_rt_sigframe *fp, frame;
int onstack;
sig_t catcher = SIGACTION(p, sig).sa_handler;
struct sigaltstack *sas = &p->p_sigctx.ps_sigstk;
tf = p->p_md.md_regs;
/* Do we need to jump onto the signal stack? */
onstack = (sas->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
(SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0;
/* Allocate space for the signal handler context. */
if (onstack)
fp = (struct linux_rt_sigframe *)((caddr_t)sas->ss_sp +
sas->ss_size);
else
fp = (struct linux_rt_sigframe *)tf->tf_esp;
fp--;
DPRINTF(("rt: onstack = %d, fp = %p sig = %d eip = 0x%x\n", onstack, fp,
sig, tf->tf_eip));
/* Build stack frame for signal trampoline. */
frame.sf_handler = catcher;
frame.sf_sig = native_to_linux_signo[sig];
frame.sf_sip = &fp->sf_si;
frame.sf_scp = &fp->sf_sc;
/*
* XXX: zero siginfo out until we provide more info.
*/
(void)memset(&frame.sf_si, 0, sizeof(frame.sf_si));
/* Save register context. */
linux_savecontext(p, tf, mask, &frame.sf_sc);
if (copyout(&frame, fp, sizeof(frame)) != 0) {
/*
* Process has trashed its stack; give it an illegal
* instruction to halt it in its tracks.
*/
sigexit(p, SIGILL);
/* NOTREACHED */
}
/*
* Build context to run handler in.
*/
tf->tf_gs = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_eip = ((int)p->p_sigctx.ps_sigcode) +
(linux_rt_sigcode - linux_sigcode);
tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
tf->tf_eflags &= ~(PSL_T|PSL_VM|PSL_AC);
tf->tf_esp = (int)fp;
tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
/* Remember that we're now on the signal stack. */
if (onstack)
sas->ss_flags |= SS_ONSTACK;
}
static void
linux_old_sendsig(sig, mask, code)
int sig;
sigset_t *mask;
u_long code;
{
struct proc *p = curproc;
struct trapframe *tf;
@ -203,58 +342,19 @@ linux_sendsig(sig, mask, code)
/* Allocate space for the signal handler context. */
if (onstack)
fp = (struct linux_sigframe *) ((caddr_t)sas->ss_sp +
sas->ss_size);
sas->ss_size);
else
fp = (struct linux_sigframe *)tf->tf_esp;
fp--;
DPRINTF((uprintf("old: onstack = %d, fp = %p sig = %d eip = 0x%x\n",
onstack, fp, sig, tf->tf_eip));
/* Build stack frame for signal trampoline. */
frame.sf_handler = catcher;
frame.sf_sig = native_to_linux_signo[sig];
frame.sf_sip = &fp->sf_si;
frame.sf_scp = &fp->sf_sc;
/*
* XXX: zero siginfo out until we provide more info.
*/
(void)memset(&frame.sf_si, 0, sizeof(frame.sf_si));
/* Save register context. */
#ifdef VM86
if (tf->tf_eflags & PSL_VM) {
frame.sf_sc.sc_gs = tf->tf_vm86_gs;
frame.sf_sc.sc_fs = tf->tf_vm86_fs;
frame.sf_sc.sc_es = tf->tf_vm86_es;
frame.sf_sc.sc_ds = tf->tf_vm86_ds;
frame.sf_sc.sc_eflags = get_vflags(p);
} else
#endif
{
frame.sf_sc.sc_gs = tf->tf_gs;
frame.sf_sc.sc_fs = tf->tf_fs;
frame.sf_sc.sc_es = tf->tf_es;
frame.sf_sc.sc_ds = tf->tf_ds;
frame.sf_sc.sc_eflags = tf->tf_eflags;
}
frame.sf_sc.sc_edi = tf->tf_edi;
frame.sf_sc.sc_esi = tf->tf_esi;
frame.sf_sc.sc_ebp = tf->tf_ebp;
frame.sf_sc.sc_ebx = tf->tf_ebx;
frame.sf_sc.sc_edx = tf->tf_edx;
frame.sf_sc.sc_ecx = tf->tf_ecx;
frame.sf_sc.sc_eax = tf->tf_eax;
frame.sf_sc.sc_eip = tf->tf_eip;
frame.sf_sc.sc_cs = tf->tf_cs;
frame.sf_sc.sc_esp_at_signal = tf->tf_esp;
frame.sf_sc.sc_ss = tf->tf_ss;
frame.sf_sc.sc_err = tf->tf_err;
frame.sf_sc.sc_trapno = tf->tf_trapno;
frame.sf_sc.sc_cr2 = p->p_addr->u_pcb.pcb_cr2;
/* Save signal stack. */
/* Linux doesn't save the onstack flag in sigframe */
/* Save signal mask. */
native_to_linux_old_sigset(&frame.sf_sc.sc_mask, mask);
linux_savecontext(p, tf, mask, &frame.sf_sc);
if (copyout(&frame, fp, sizeof(frame)) != 0) {
/*
@ -325,17 +425,22 @@ linux_sys_sigreturn(p, v, retval)
*/
scp = SCARG(uap, scp);
if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
return (EFAULT);
return EFAULT;
/* Restore register context. */
tf = p->p_md.md_regs;
DPRINTF(("sigreturn enter esp=%x eip=%x\n", tf->tf_esp, tf->tf_eip));
#ifdef VM86
if (context.sc_eflags & PSL_VM) {
void syscall_vm86 __P((struct trapframe));
tf->tf_vm86_gs = context.sc_gs;
tf->tf_vm86_fs = context.sc_fs;
tf->tf_vm86_es = context.sc_es;
tf->tf_vm86_ds = context.sc_ds;
set_vflags(p, context.sc_eflags);
p->p_md.md_syscall = syscall_vm86;
} else
#endif
{
@ -347,12 +452,16 @@ linux_sys_sigreturn(p, v, retval)
*/
if (((context.sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 ||
!USERMODE(context.sc_cs, context.sc_eflags))
return (EINVAL);
return EINVAL;
tf->tf_gs = context.sc_gs;
tf->tf_fs = context.sc_fs;
tf->tf_es = context.sc_es;
tf->tf_ds = context.sc_ds;
#ifdef VM86
if (tf->tf_eflags & PSL_VM)
(*p->p_emul->e_syscall_intern)(p);
#endif
tf->tf_eflags = context.sc_eflags;
}
tf->tf_edi = context.sc_edi;
@ -382,8 +491,8 @@ linux_sys_sigreturn(p, v, retval)
/* Restore signal mask. */
linux_old_to_native_sigset(&mask, &context.sc_mask);
(void) sigprocmask1(p, SIG_SETMASK, &mask, 0);
return (EJUSTRETURN);
DPRINTF(("sigreturn exit esp=%x eip=%x\n", tf->tf_esp, tf->tf_eip));
return EJUSTRETURN;
}
#ifdef USER_LDT

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_machdep.h,v 1.24 2002/11/26 18:42:38 christos Exp $ */
/* $NetBSD: linux_machdep.h,v 1.25 2002/12/06 00:02:59 christos Exp $ */
/*-
* Copyright (c) 1995, 2000 The NetBSD Foundation, Inc.
@ -46,6 +46,40 @@
/*
* The Linux sigcontext, pretty much a standard 386 trapframe.
*/
struct linux_fpreg {
uint16_t mant[4];
uint16_t expo;
};
struct linux_fpxreg {
uint16_t mant[4];
uint16_t expo;
uint16_t pad[3];
};
struct linux_xmmreg {
uint32_t reg[4];
};
struct linux_fpstate {
uint32_t cw;
uint32_t sw;
uint32_t tag;
uint32_t ipoff;
uint32_t cssel;
uint32_t dataoff;
uint32_t datasel;
struct linux_fpreg st[8];
uint16_t status;
uint16_t magic;
uint32_t fxsr_env[6];
uint32_t mxcsr;
uint32_t reserved;
struct linux_fpxreg fxsr_st[8];
struct linux_xmmreg xmm[8];
uint32_t padding[56];
};
struct linux_sigcontext {
int sc_gs;
@ -67,7 +101,7 @@ struct linux_sigcontext {
int sc_eflags;
int sc_esp_at_signal;
int sc_ss;
int sc_387;
struct linux_fpstate *sc_387;
/* XXX check this */
linux_old_sigset_t sc_mask;
int sc_cr2;
@ -79,14 +113,19 @@ struct linux_sigcontext {
* This means that we need to pass the pointer to the handler too.
* It is appended to the frame to not interfere with the rest of it.
*/
struct linux_sigframe {
struct linux_rt_sigframe {
int sf_sig;
struct linux_siginfo *sf_sip;
struct linux_sigcontext *sf_scp;
sig_t sf_handler;
struct linux_siginfo sf_si;
struct linux_sigcontext sf_sc;
sig_t sf_handler;
};
struct linux_sigframe {
int sf_sig;
struct linux_sigcontext sf_sc;
sig_t sf_handler;
};
#ifdef _KERNEL