Commit f344ba49 authored by David S. Miller's avatar David S. Miller

[SPARC]: Report si_addr in SIGINFO more accurately.

parent 71279d2b
...@@ -137,7 +137,7 @@ static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *re ...@@ -137,7 +137,7 @@ static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *re
return &win->locals[reg - 16]; return &win->locals[reg - 16];
} }
static inline unsigned long compute_effective_address(struct pt_regs *regs, static unsigned long compute_effective_address(struct pt_regs *regs,
unsigned int insn) unsigned int insn)
{ {
unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs1 = (insn >> 14) & 0x1f;
...@@ -153,7 +153,7 @@ static inline unsigned long compute_effective_address(struct pt_regs *regs, ...@@ -153,7 +153,7 @@ static inline unsigned long compute_effective_address(struct pt_regs *regs,
} }
} }
static inline unsigned long safe_compute_effective_address(struct pt_regs *regs, unsigned long safe_compute_effective_address(struct pt_regs *regs,
unsigned int insn) unsigned int insn)
{ {
unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs1 = (insn >> 14) & 0x1f;
......
...@@ -201,6 +201,25 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, ...@@ -201,6 +201,25 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
return 0; return 0;
} }
extern unsigned long safe_compute_effective_address(struct pt_regs *,
unsigned int);
static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)
{
unsigned int insn;
if (text_fault)
return regs->pc;
if (regs->psr & PSR_PS) {
insn = *(unsigned int *) regs->pc;
} else {
__get_user(insn, (unsigned int *) regs->pc);
}
return safe_compute_effective_address(regs, insn);
}
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)
{ {
...@@ -307,7 +326,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, ...@@ -307,7 +326,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
info.si_errno = 0; info.si_errno = 0;
/* info.si_code set above to make clear whether /* info.si_code set above to make clear whether
this was a SEGV_MAPERR or SEGV_ACCERR fault. */ this was a SEGV_MAPERR or SEGV_ACCERR fault. */
info.si_addr = (void *)address; info.si_addr = (void *) compute_si_addr(regs, text_fault);
info.si_trapno = 0; info.si_trapno = 0;
force_sig_info (SIGSEGV, &info, tsk); force_sig_info (SIGSEGV, &info, tsk);
return; return;
...@@ -361,7 +380,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, ...@@ -361,7 +380,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
info.si_signo = SIGBUS; info.si_signo = SIGBUS;
info.si_errno = 0; info.si_errno = 0;
info.si_code = BUS_ADRERR; info.si_code = BUS_ADRERR;
info.si_addr = (void *)address; info.si_addr = (void *) compute_si_addr(regs, text_fault);
info.si_trapno = 0; info.si_trapno = 0;
force_sig_info (SIGBUS, &info, tsk); force_sig_info (SIGBUS, &info, tsk);
if (!from_user) if (!from_user)
...@@ -530,7 +549,7 @@ inline void force_user_fault(unsigned long address, int write) ...@@ -530,7 +549,7 @@ inline void force_user_fault(unsigned long address, int write)
info.si_errno = 0; info.si_errno = 0;
/* info.si_code set above to make clear whether /* info.si_code set above to make clear whether
this was a SEGV_MAPERR or SEGV_ACCERR fault. */ this was a SEGV_MAPERR or SEGV_ACCERR fault. */
info.si_addr = (void *)address; info.si_addr = (void *) address;
info.si_trapno = 0; info.si_trapno = 0;
force_sig_info (SIGSEGV, &info, tsk); force_sig_info (SIGSEGV, &info, tsk);
return; return;
...@@ -540,7 +559,7 @@ inline void force_user_fault(unsigned long address, int write) ...@@ -540,7 +559,7 @@ inline void force_user_fault(unsigned long address, int write)
info.si_signo = SIGBUS; info.si_signo = SIGBUS;
info.si_errno = 0; info.si_errno = 0;
info.si_code = BUS_ADRERR; info.si_code = BUS_ADRERR;
info.si_addr = (void *)address; info.si_addr = (void *) address;
info.si_trapno = 0; info.si_trapno = 0;
force_sig_info (SIGBUS, &info, tsk); force_sig_info (SIGBUS, &info, tsk);
} }
......
...@@ -158,7 +158,7 @@ static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) ...@@ -158,7 +158,7 @@ static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
} }
} }
static unsigned long compute_effective_address(struct pt_regs *regs, unsigned long compute_effective_address(struct pt_regs *regs,
unsigned int insn, unsigned int rd) unsigned int insn, unsigned int rd)
{ {
unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs1 = (insn >> 14) & 0x1f;
......
...@@ -207,14 +207,21 @@ static unsigned int get_user_insn(unsigned long tpc) ...@@ -207,14 +207,21 @@ static unsigned int get_user_insn(unsigned long tpc)
return insn; return insn;
} }
static void do_fault_siginfo(int code, int sig, unsigned long address) 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,
unsigned int insn, int fault_code)
{ {
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;
info.si_addr = (void *) address; if (fault_code & FAULT_CODE_ITLB)
info.si_addr = (void *) regs->tpc;
else
info.si_addr = (void *)
compute_effective_address(regs, insn, 0);
info.si_trapno = 0; info.si_trapno = 0;
force_sig_info(sig, &info, current); force_sig_info(sig, &info, current);
} }
...@@ -295,7 +302,7 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, ...@@ -295,7 +302,7 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
/* The si_code was set to make clear whether /* The si_code was set to make clear whether
* this was a SEGV_MAPERR or SEGV_ACCERR fault. * this was a SEGV_MAPERR or SEGV_ACCERR fault.
*/ */
do_fault_siginfo(si_code, SIGSEGV, address); do_fault_siginfo(si_code, SIGSEGV, regs, insn, fault_code);
return; return;
} }
...@@ -471,7 +478,7 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs) ...@@ -471,7 +478,7 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs)
* Send a sigbus, regardless of whether we were in kernel * Send a sigbus, regardless of whether we were in kernel
* or user mode. * or user mode.
*/ */
do_fault_siginfo(BUS_ADRERR, SIGBUS, address); do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, insn, fault_code);
/* Kernel mode? Handle exceptions or die */ /* Kernel mode? Handle exceptions or die */
if (regs->tstate & TSTATE_PRIV) if (regs->tstate & TSTATE_PRIV)
......
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