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:
parent
c363ae66f1
commit
ef042d8e23
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user