Commit 4b177647 authored by David S. Miller's avatar David S. Miller

sparc: Support show_unhandled_signals.

Just faults right now, will add other traps later.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c7ec2b58
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
extern int prom_node_root; extern int prom_node_root;
int show_unhandled_signals = 1;
/* At boot time we determine these two values necessary for setting /* At boot time we determine these two values necessary for setting
* up the segment maps and page table entries (pte's). * up the segment maps and page table entries (pte's).
*/ */
...@@ -149,6 +151,45 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, ...@@ -149,6 +151,45 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
return 0; return 0;
} }
static inline void
show_signal_msg(struct pt_regs *regs, int sig, int code,
unsigned long address, struct task_struct *tsk)
{
if (!unhandled_signal(tsk, sig))
return;
if (!printk_ratelimit())
return;
printk("%s%s[%d]: segfault at %lx ip %p (rpc %p) sp %p error %x",
task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
tsk->comm, task_pid_nr(tsk), address,
(void *)regs->pc, (void *)regs->u_regs[UREG_I7],
(void *)regs->u_regs[UREG_FP], code);
print_vma_addr(KERN_CONT " in ", regs->pc);
printk(KERN_CONT "\n");
}
static void __do_fault_siginfo(int code, int sig, struct pt_regs *regs,
unsigned long addr)
{
siginfo_t info;
info.si_signo = sig;
info.si_code = code;
info.si_errno = 0;
info.si_addr = (void __user *) addr;
info.si_trapno = 0;
if (unlikely(show_unhandled_signals))
show_signal_msg(regs, sig, info.si_code,
addr, current);
force_sig_info (sig, &info, current);
}
extern unsigned long safe_compute_effective_address(struct pt_regs *, extern unsigned long safe_compute_effective_address(struct pt_regs *,
unsigned int); unsigned int);
...@@ -168,6 +209,14 @@ static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault) ...@@ -168,6 +209,14 @@ static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)
return safe_compute_effective_address(regs, insn); return safe_compute_effective_address(regs, insn);
} }
static noinline void do_fault_siginfo(int code, int sig, struct pt_regs *regs,
int text_fault)
{
unsigned long addr = compute_si_addr(regs, text_fault);
__do_fault_siginfo(code, sig, regs, addr);
}
asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
unsigned long address) unsigned long address)
{ {
...@@ -176,9 +225,8 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, ...@@ -176,9 +225,8 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
struct mm_struct *mm = tsk->mm; struct mm_struct *mm = tsk->mm;
unsigned int fixup; unsigned int fixup;
unsigned long g2; unsigned long g2;
siginfo_t info;
int from_user = !(regs->psr & PSR_PS); int from_user = !(regs->psr & PSR_PS);
int fault; int fault, code;
if(text_fault) if(text_fault)
address = regs->pc; address = regs->pc;
...@@ -195,7 +243,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, ...@@ -195,7 +243,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
if (!ARCH_SUN4C && address >= TASK_SIZE) if (!ARCH_SUN4C && address >= TASK_SIZE)
goto vmalloc_fault; goto vmalloc_fault;
info.si_code = SEGV_MAPERR; code = SEGV_MAPERR;
/* /*
* If we're in an interrupt or have no user * If we're in an interrupt or have no user
...@@ -229,7 +277,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, ...@@ -229,7 +277,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
* we can handle it.. * we can handle it..
*/ */
good_area: good_area:
info.si_code = SEGV_ACCERR; code = SEGV_ACCERR;
if(write) { if(write) {
if(!(vma->vm_flags & VM_WRITE)) if(!(vma->vm_flags & VM_WRITE))
goto bad_area; goto bad_area;
...@@ -273,18 +321,8 @@ bad_area: ...@@ -273,18 +321,8 @@ bad_area:
bad_area_nosemaphore: bad_area_nosemaphore:
/* User mode accesses just cause a SIGSEGV */ /* User mode accesses just cause a SIGSEGV */
if(from_user) { if (from_user) {
#if 0 do_fault_siginfo(code, SIGSEGV, regs, text_fault);
printk("Fault whee %s [%d]: segfaults at %08lx pc=%08lx\n",
tsk->comm, tsk->pid, address, regs->pc);
#endif
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* info.si_code set above to make clear whether
this was a SEGV_MAPERR or SEGV_ACCERR fault. */
info.si_addr = (void __user *)compute_si_addr(regs, text_fault);
info.si_trapno = 0;
force_sig_info (SIGSEGV, &info, tsk);
return; return;
} }
...@@ -335,12 +373,7 @@ out_of_memory: ...@@ -335,12 +373,7 @@ out_of_memory:
do_sigbus: do_sigbus:
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
info.si_signo = SIGBUS; do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, text_fault);
info.si_errno = 0;
info.si_code = BUS_ADRERR;
info.si_addr = (void __user *) compute_si_addr(regs, text_fault);
info.si_trapno = 0;
force_sig_info (SIGBUS, &info, tsk);
if (!from_user) if (!from_user)
goto no_context; goto no_context;
...@@ -466,14 +499,10 @@ static void force_user_fault(unsigned long address, int write) ...@@ -466,14 +499,10 @@ static void force_user_fault(unsigned long address, int write)
struct vm_area_struct *vma; struct vm_area_struct *vma;
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm; struct mm_struct *mm = tsk->mm;
siginfo_t info; int code;
info.si_code = SEGV_MAPERR; code = SEGV_MAPERR;
#if 0
printk("wf<pid=%d,wr=%d,addr=%08lx>\n",
tsk->pid, write, address);
#endif
down_read(&mm->mmap_sem); down_read(&mm->mmap_sem);
vma = find_vma(mm, address); vma = find_vma(mm, address);
if(!vma) if(!vma)
...@@ -485,7 +514,7 @@ static void force_user_fault(unsigned long address, int write) ...@@ -485,7 +514,7 @@ static void force_user_fault(unsigned long address, int write)
if(expand_stack(vma, address)) if(expand_stack(vma, address))
goto bad_area; goto bad_area;
good_area: good_area:
info.si_code = SEGV_ACCERR; code = SEGV_ACCERR;
if(write) { if(write) {
if(!(vma->vm_flags & VM_WRITE)) if(!(vma->vm_flags & VM_WRITE))
goto bad_area; goto bad_area;
...@@ -502,27 +531,12 @@ good_area: ...@@ -502,27 +531,12 @@ good_area:
return; return;
bad_area: bad_area:
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
#if 0 __do_fault_siginfo(code, SIGSEGV, tsk->thread.kregs, address);
printk("Window whee %s [%d]: segfaults at %08lx\n",
tsk->comm, tsk->pid, address);
#endif
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* info.si_code set above to make clear whether
this was a SEGV_MAPERR or SEGV_ACCERR fault. */
info.si_addr = (void __user *) address;
info.si_trapno = 0;
force_sig_info (SIGSEGV, &info, tsk);
return; return;
do_sigbus: do_sigbus:
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
info.si_signo = SIGBUS; __do_fault_siginfo(BUS_ADRERR, SIGBUS, tsk->thread.kregs, address);
info.si_errno = 0;
info.si_code = BUS_ADRERR;
info.si_addr = (void __user *) address;
info.si_trapno = 0;
force_sig_info (SIGBUS, &info, tsk);
} }
void window_overflow_fault(void) void window_overflow_fault(void)
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
int show_unhandled_signals = 1;
static inline __kprobes int notify_page_fault(struct pt_regs *regs) static inline __kprobes int notify_page_fault(struct pt_regs *regs)
{ {
int ret = 0; int ret = 0;
...@@ -128,22 +130,48 @@ outret: ...@@ -128,22 +130,48 @@ outret:
return insn; return insn;
} }
static inline void
show_signal_msg(struct pt_regs *regs, int sig, int code,
unsigned long address, struct task_struct *tsk)
{
if (!unhandled_signal(tsk, sig))
return;
if (!printk_ratelimit())
return;
printk("%s%s[%d]: segfault at %lx ip %p (rpc %p) sp %p error %x",
task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
tsk->comm, task_pid_nr(tsk), address,
(void *)regs->tpc, (void *)regs->u_regs[UREG_I7],
(void *)regs->u_regs[UREG_FP], code);
print_vma_addr(KERN_CONT " in ", regs->tpc);
printk(KERN_CONT "\n");
}
extern unsigned long compute_effective_address(struct pt_regs *, unsigned int, unsigned int); extern unsigned long compute_effective_address(struct pt_regs *, unsigned int, unsigned int);
static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, static void do_fault_siginfo(int code, int sig, struct pt_regs *regs,
unsigned int insn, int fault_code) unsigned int insn, int fault_code)
{ {
unsigned long addr;
siginfo_t info; siginfo_t info;
info.si_code = code; info.si_code = code;
info.si_signo = sig; info.si_signo = sig;
info.si_errno = 0; info.si_errno = 0;
if (fault_code & FAULT_CODE_ITLB) if (fault_code & FAULT_CODE_ITLB)
info.si_addr = (void __user *) regs->tpc; addr = regs->tpc;
else else
info.si_addr = (void __user *) addr = compute_effective_address(regs, insn, 0);
compute_effective_address(regs, insn, 0); info.si_addr = (void __user *) addr;
info.si_trapno = 0; info.si_trapno = 0;
if (unlikely(show_unhandled_signals))
show_signal_msg(regs, sig, code, addr, current);
force_sig_info(sig, &info, current); force_sig_info(sig, &info, current);
} }
......
...@@ -1441,7 +1441,7 @@ static struct ctl_table fs_table[] = { ...@@ -1441,7 +1441,7 @@ static struct ctl_table fs_table[] = {
}; };
static struct ctl_table debug_table[] = { static struct ctl_table debug_table[] = {
#if defined(CONFIG_X86) || defined(CONFIG_PPC) #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC)
{ {
.procname = "exception-trace", .procname = "exception-trace",
.data = &show_unhandled_signals, .data = &show_unhandled_signals,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment