Messages in this thread Patches in this message | | | Date | Thu, 14 Sep 2006 04:34:00 -0400 | From | "Albert Cahalan" <> | Subject | [PATCH] i386/x86_64 signal handler arg fixes |
| |
Some time ago, the i386 kernel was patched to support user code that has signal handlers marked with __attribute__((regparm(3))) or compiled with the -mregparm=3 gcc option. This is useful for klibc at least. The code wasn't quite right, and it never got ported to x86_64.
For i386, the non-RT frame is wrong. It was using the raw sig value instead of the translated value, and did not pass the semi-documented extra parameters.
For x86-64, the regparm 3 calling convention was simply missing.
This patch should do the job, provided I'm right in guessing that a struct passed by value is really passed as a pointer in this case. (the non-RT signal handler's second arg is a pass-by-value struct)
Signed-off-by: Albert Cahalan <acahalan@gmail.com> --- I'm sending this inline for review, and attached because the whitespace will surely be mangled.
diff -Naurd old/arch/i386/kernel/signal.c new/arch/i386/kernel/signal.c --- old/arch/i386/kernel/signal.c 2006-09-14 03:49:30.000000000 -0400 +++ new/arch/i386/kernel/signal.c 2006-09-14 03:52:54.000000000 -0400 @@ -375,9 +375,9 @@ /* Set up registers for signal handler */ regs->esp = (unsigned long) frame; regs->eip = (unsigned long) ka->sa.sa_handler; - regs->eax = (unsigned long) sig; - regs->edx = (unsigned long) 0; - regs->ecx = (unsigned long) 0; + regs->eax = (unsigned long) usig; + regs->edx = (unsigned long) &frame->sc; + regs->ecx = (unsigned long) &frame->fpstate;
set_fs(USER_DS); regs->xds = __USER_DS; diff -Naurd old/arch/x86_64/ia32/ia32_signal.c new/arch/x86_64/ia32/ia32_signal.c --- old/arch/x86_64/ia32/ia32_signal.c 2006-09-14 03:21:21.000000000 -0400 +++ new/arch/x86_64/ia32/ia32_signal.c 2006-09-14 03:47:32.000000000 -0400 @@ -433,6 +433,7 @@ { struct sigframe __user *frame; int err = 0; + int usig;
frame = get_sigframe(ka, regs, sizeof(*frame));
@@ -441,12 +442,10 @@
{ struct exec_domain *ed = current_thread_info()->exec_domain; - err |= __put_user((ed - && ed->signal_invmap - && sig < 32 - ? ed->signal_invmap[sig] - : sig), - &frame->sig); + usig = ed && ed->signal_invmap && sig < 32 + ? ed->signal_invmap[sig] + : sig; + err |= __put_user(usig,&frame->sig); } if (err) goto give_sigsegv; @@ -493,6 +492,9 @@ /* Set up registers for signal handler */ regs->rsp = (unsigned long) frame; regs->rip = (unsigned long) ka->sa.sa_handler; + regs->rax = (unsigned long) usig; + regs->rdx = (unsigned long) &frame->sc; + regs->rcx = (unsigned long) &frame->fpstate;
asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); @@ -522,6 +524,7 @@ { struct rt_sigframe __user *frame; int err = 0; + int usig;
frame = get_sigframe(ka, regs, sizeof(*frame));
@@ -530,12 +533,10 @@
{ struct exec_domain *ed = current_thread_info()->exec_domain; - err |= __put_user((ed - && ed->signal_invmap - && sig < 32 - ? ed->signal_invmap[sig] - : sig), - &frame->sig); + usig = ed && ed->signal_invmap && sig < 32 + ? ed->signal_invmap[sig] + : sig; + err |= __put_user(usig,&frame->sig); } err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo); err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc); @@ -589,6 +590,9 @@ /* Set up registers for signal handler */ regs->rsp = (unsigned long) frame; regs->rip = (unsigned long) ka->sa.sa_handler; + regs->rax = (unsigned long) usig; + regs->rdx = (unsigned long) &frame->info; + regs->rcx = (unsigned long) &frame->uc;
asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); asm volatile("movl %0,%%es" :: "r" (__USER32_DS));diff -Naurd old/arch/i386/kernel/signal.c new/arch/i386/kernel/signal.c --- old/arch/i386/kernel/signal.c 2006-09-14 03:49:30.000000000 -0400 +++ new/arch/i386/kernel/signal.c 2006-09-14 03:52:54.000000000 -0400 @@ -375,9 +375,9 @@ /* Set up registers for signal handler */ regs->esp = (unsigned long) frame; regs->eip = (unsigned long) ka->sa.sa_handler; - regs->eax = (unsigned long) sig; - regs->edx = (unsigned long) 0; - regs->ecx = (unsigned long) 0; + regs->eax = (unsigned long) usig; + regs->edx = (unsigned long) &frame->sc; + regs->ecx = (unsigned long) &frame->fpstate; set_fs(USER_DS); regs->xds = __USER_DS; diff -Naurd old/arch/x86_64/ia32/ia32_signal.c new/arch/x86_64/ia32/ia32_signal.c --- old/arch/x86_64/ia32/ia32_signal.c 2006-09-14 03:21:21.000000000 -0400 +++ new/arch/x86_64/ia32/ia32_signal.c 2006-09-14 03:47:32.000000000 -0400 @@ -433,6 +433,7 @@ { struct sigframe __user *frame; int err = 0; + int usig; frame = get_sigframe(ka, regs, sizeof(*frame)); @@ -441,12 +442,10 @@ { struct exec_domain *ed = current_thread_info()->exec_domain; - err |= __put_user((ed - && ed->signal_invmap - && sig < 32 - ? ed->signal_invmap[sig] - : sig), - &frame->sig); + usig = ed && ed->signal_invmap && sig < 32 + ? ed->signal_invmap[sig] + : sig; + err |= __put_user(usig,&frame->sig); } if (err) goto give_sigsegv; @@ -493,6 +492,9 @@ /* Set up registers for signal handler */ regs->rsp = (unsigned long) frame; regs->rip = (unsigned long) ka->sa.sa_handler; + regs->rax = (unsigned long) usig; + regs->rdx = (unsigned long) &frame->sc; + regs->rcx = (unsigned long) &frame->fpstate; asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); @@ -522,6 +524,7 @@ { struct rt_sigframe __user *frame; int err = 0; + int usig; frame = get_sigframe(ka, regs, sizeof(*frame)); @@ -530,12 +533,10 @@ { struct exec_domain *ed = current_thread_info()->exec_domain; - err |= __put_user((ed - && ed->signal_invmap - && sig < 32 - ? ed->signal_invmap[sig] - : sig), - &frame->sig); + usig = ed && ed->signal_invmap && sig < 32 + ? ed->signal_invmap[sig] + : sig; + err |= __put_user(usig,&frame->sig); } err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo); err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc); @@ -589,6 +590,9 @@ /* Set up registers for signal handler */ regs->rsp = (unsigned long) frame; regs->rip = (unsigned long) ka->sa.sa_handler; + regs->rax = (unsigned long) usig; + regs->rdx = (unsigned long) &frame->info; + regs->rcx = (unsigned long) &frame->uc; asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); | |