[POWERPC] Implement logging of unhandled signals
Implement show_unhandled_signals sysctl + support to print when a process is killed due to unhandled signals just as i386 and x86_64 does. Default to having it off, unlike x86 that defaults on. Signed-off-by: Olof Johansson <olof@lixom.net> Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
Родитель
b63db45ca4
Коммит
d0c3d534a4
|
@ -16,6 +16,12 @@
|
||||||
|
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
|
|
||||||
|
/* Log an error when sending an unhandled signal to a process. Controlled
|
||||||
|
* through debug.exception-trace sysctl.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int show_unhandled_signals = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate space for the signal frame
|
* Allocate space for the signal frame
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -705,11 +705,13 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||||
{
|
{
|
||||||
struct rt_sigframe __user *rt_sf;
|
struct rt_sigframe __user *rt_sf;
|
||||||
struct mcontext __user *frame;
|
struct mcontext __user *frame;
|
||||||
|
void __user *addr;
|
||||||
unsigned long newsp = 0;
|
unsigned long newsp = 0;
|
||||||
|
|
||||||
/* Set up Signal Frame */
|
/* Set up Signal Frame */
|
||||||
/* Put a Real Time Context onto stack */
|
/* Put a Real Time Context onto stack */
|
||||||
rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf));
|
rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf));
|
||||||
|
addr = rt_sf;
|
||||||
if (unlikely(rt_sf == NULL))
|
if (unlikely(rt_sf == NULL))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
|
@ -728,6 +730,7 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||||
|
|
||||||
/* Save user registers on the stack */
|
/* Save user registers on the stack */
|
||||||
frame = &rt_sf->uc.uc_mcontext;
|
frame = &rt_sf->uc.uc_mcontext;
|
||||||
|
addr = frame;
|
||||||
if (vdso32_rt_sigtramp && current->mm->context.vdso_base) {
|
if (vdso32_rt_sigtramp && current->mm->context.vdso_base) {
|
||||||
if (save_user_regs(regs, frame, 0))
|
if (save_user_regs(regs, frame, 0))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
@ -742,6 +745,7 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
|
||||||
|
|
||||||
/* create a stack frame for the caller of the handler */
|
/* create a stack frame for the caller of the handler */
|
||||||
newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16);
|
newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16);
|
||||||
|
addr = (void __user *)regs->gpr[1];
|
||||||
if (put_user(regs->gpr[1], (u32 __user *)newsp))
|
if (put_user(regs->gpr[1], (u32 __user *)newsp))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
|
@ -762,6 +766,12 @@ badframe:
|
||||||
printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",
|
printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",
|
||||||
regs, frame, newsp);
|
regs, frame, newsp);
|
||||||
#endif
|
#endif
|
||||||
|
if (show_unhandled_signals && printk_ratelimit())
|
||||||
|
printk(KERN_INFO "%s[%d]: bad frame in handle_rt_signal32: "
|
||||||
|
"%p nip %08lx lr %08lx\n",
|
||||||
|
current->comm, current->pid,
|
||||||
|
addr, regs->nip, regs->link);
|
||||||
|
|
||||||
force_sigsegv(sig, current);
|
force_sigsegv(sig, current);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -886,6 +896,12 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
|
if (show_unhandled_signals && printk_ratelimit())
|
||||||
|
printk(KERN_INFO "%s[%d]: bad frame in sys_rt_sigreturn: "
|
||||||
|
"%p nip %08lx lr %08lx\n",
|
||||||
|
current->comm, current->pid,
|
||||||
|
rt_sf, regs->nip, regs->link);
|
||||||
|
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -967,6 +983,13 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
|
||||||
* We kill the task with a SIGSEGV in this situation.
|
* We kill the task with a SIGSEGV in this situation.
|
||||||
*/
|
*/
|
||||||
if (do_setcontext(ctx, regs, 1)) {
|
if (do_setcontext(ctx, regs, 1)) {
|
||||||
|
if (show_unhandled_signals && printk_ratelimit())
|
||||||
|
printk(KERN_INFO "%s[%d]: bad frame in "
|
||||||
|
"sys_debug_setcontext: %p nip %08lx "
|
||||||
|
"lr %08lx\n",
|
||||||
|
current->comm, current->pid,
|
||||||
|
ctx, regs->nip, regs->link);
|
||||||
|
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1048,6 +1071,12 @@ badframe:
|
||||||
printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n",
|
printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n",
|
||||||
regs, frame, newsp);
|
regs, frame, newsp);
|
||||||
#endif
|
#endif
|
||||||
|
if (show_unhandled_signals && printk_ratelimit())
|
||||||
|
printk(KERN_INFO "%s[%d]: bad frame in handle_signal32: "
|
||||||
|
"%p nip %08lx lr %08lx\n",
|
||||||
|
current->comm, current->pid,
|
||||||
|
frame, regs->nip, regs->link);
|
||||||
|
|
||||||
force_sigsegv(sig, current);
|
force_sigsegv(sig, current);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1061,12 +1090,14 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
|
||||||
struct sigcontext __user *sc;
|
struct sigcontext __user *sc;
|
||||||
struct sigcontext sigctx;
|
struct sigcontext sigctx;
|
||||||
struct mcontext __user *sr;
|
struct mcontext __user *sr;
|
||||||
|
void __user *addr;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
|
|
||||||
/* Always make any pending restarted system calls return -EINTR */
|
/* Always make any pending restarted system calls return -EINTR */
|
||||||
current_thread_info()->restart_block.fn = do_no_restart_syscall;
|
current_thread_info()->restart_block.fn = do_no_restart_syscall;
|
||||||
|
|
||||||
sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
|
sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
|
||||||
|
addr = sc;
|
||||||
if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
|
if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
|
@ -1083,6 +1114,7 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
|
||||||
restore_sigmask(&set);
|
restore_sigmask(&set);
|
||||||
|
|
||||||
sr = (struct mcontext __user *)from_user_ptr(sigctx.regs);
|
sr = (struct mcontext __user *)from_user_ptr(sigctx.regs);
|
||||||
|
addr = sr;
|
||||||
if (!access_ok(VERIFY_READ, sr, sizeof(*sr))
|
if (!access_ok(VERIFY_READ, sr, sizeof(*sr))
|
||||||
|| restore_user_regs(regs, sr, 1))
|
|| restore_user_regs(regs, sr, 1))
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
@ -1091,6 +1123,12 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
|
if (show_unhandled_signals && printk_ratelimit())
|
||||||
|
printk(KERN_INFO "%s[%d]: bad frame in sys_sigreturn: "
|
||||||
|
"%p nip %08lx lr %08lx\n",
|
||||||
|
current->comm, current->pid,
|
||||||
|
addr, regs->nip, regs->link);
|
||||||
|
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,11 @@ struct rt_sigframe {
|
||||||
char abigap[288];
|
char abigap[288];
|
||||||
} __attribute__ ((aligned (16)));
|
} __attribute__ ((aligned (16)));
|
||||||
|
|
||||||
|
static const char fmt32[] = KERN_INFO \
|
||||||
|
"%s[%d]: bad frame in %s: %08lx nip %08lx lr %08lx\n";
|
||||||
|
static const char fmt64[] = KERN_INFO \
|
||||||
|
"%s[%d]: bad frame in %s: %016lx nip %016lx lr %016lx\n";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up the sigcontext for the signal frame.
|
* Set up the sigcontext for the signal frame.
|
||||||
*/
|
*/
|
||||||
|
@ -315,6 +320,11 @@ badframe:
|
||||||
printk("badframe in sys_rt_sigreturn, regs=%p uc=%p &uc->uc_mcontext=%p\n",
|
printk("badframe in sys_rt_sigreturn, regs=%p uc=%p &uc->uc_mcontext=%p\n",
|
||||||
regs, uc, &uc->uc_mcontext);
|
regs, uc, &uc->uc_mcontext);
|
||||||
#endif
|
#endif
|
||||||
|
if (show_unhandled_signals && printk_ratelimit())
|
||||||
|
printk(regs->msr & MSR_SF ? fmt64 : fmt32,
|
||||||
|
current->comm, current->pid, "rt_sigreturn",
|
||||||
|
(long)uc, regs->nip, regs->link);
|
||||||
|
|
||||||
force_sig(SIGSEGV, current);
|
force_sig(SIGSEGV, current);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -398,6 +408,11 @@ badframe:
|
||||||
printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
|
printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
|
||||||
regs, frame, newsp);
|
regs, frame, newsp);
|
||||||
#endif
|
#endif
|
||||||
|
if (show_unhandled_signals && printk_ratelimit())
|
||||||
|
printk(regs->msr & MSR_SF ? fmt64 : fmt32,
|
||||||
|
current->comm, current->pid, "setup_rt_frame",
|
||||||
|
(long)frame, regs->nip, regs->link);
|
||||||
|
|
||||||
force_sigsegv(signr, current);
|
force_sigsegv(signr, current);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,11 +172,21 @@ int die(const char *str, struct pt_regs *regs, long err)
|
||||||
void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
|
void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
|
||||||
{
|
{
|
||||||
siginfo_t info;
|
siginfo_t info;
|
||||||
|
const char fmt32[] = KERN_INFO "%s[%d]: unhandled signal %d " \
|
||||||
|
"at %08lx nip %08lx lr %08lx code %x\n";
|
||||||
|
const char fmt64[] = KERN_INFO "%s[%d]: unhandled signal %d " \
|
||||||
|
"at %016lx nip %016lx lr %016lx code %x\n";
|
||||||
|
|
||||||
if (!user_mode(regs)) {
|
if (!user_mode(regs)) {
|
||||||
if (die("Exception in kernel mode", regs, signr))
|
if (die("Exception in kernel mode", regs, signr))
|
||||||
return;
|
return;
|
||||||
}
|
} else if (show_unhandled_signals &&
|
||||||
|
unhandled_signal(current, signr) &&
|
||||||
|
printk_ratelimit()) {
|
||||||
|
printk(regs->msr & MSR_SF ? fmt64 : fmt32,
|
||||||
|
current->comm, current->pid, signr,
|
||||||
|
addr, regs->nip, regs->link, code);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&info, 0, sizeof(info));
|
memset(&info, 0, sizeof(info));
|
||||||
info.si_signo = signr;
|
info.si_signo = signr;
|
||||||
|
|
|
@ -1221,7 +1221,7 @@ static ctl_table fs_table[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static ctl_table debug_table[] = {
|
static ctl_table debug_table[] = {
|
||||||
#ifdef CONFIG_X86
|
#if defined(CONFIG_X86) || defined(CONFIG_PPC)
|
||||||
{
|
{
|
||||||
.ctl_name = CTL_UNNUMBERED,
|
.ctl_name = CTL_UNNUMBERED,
|
||||||
.procname = "exception-trace",
|
.procname = "exception-trace",
|
||||||
|
|
Загрузка…
Ссылка в новой задаче