]> git.hungrycats.org Git - linux/commitdiff
[SPARC]: Report si_addr in SIGINFO more accurately.
authorDavid S. Miller <davem@nuts.davemloft.net>
Tue, 15 Jun 2004 13:05:46 +0000 (06:05 -0700)
committerDavid S. Miller <davem@nuts.davemloft.net>
Tue, 15 Jun 2004 13:05:46 +0000 (06:05 -0700)
arch/sparc/kernel/unaligned.c
arch/sparc/mm/fault.c
arch/sparc64/kernel/unaligned.c
arch/sparc64/mm/fault.c

index 3a1ccaccb0a98f301188e4d73bc309626d0344f1..a9a9e0c73ae4cad986022600dbe9d291760cf3d9 100644 (file)
@@ -137,8 +137,8 @@ static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *re
        return &win->locals[reg - 16];
 }
 
-static inline unsigned long compute_effective_address(struct pt_regs *regs,
-                                                     unsigned int insn)
+static unsigned long compute_effective_address(struct pt_regs *regs,
+                                              unsigned int insn)
 {
        unsigned int rs1 = (insn >> 14) & 0x1f;
        unsigned int rs2 = insn & 0x1f;
@@ -153,8 +153,8 @@ static inline unsigned long compute_effective_address(struct pt_regs *regs,
        }
 }
 
-static inline unsigned long safe_compute_effective_address(struct pt_regs *regs,
-                                                          unsigned int insn)
+unsigned long safe_compute_effective_address(struct pt_regs *regs,
+                                            unsigned int insn)
 {
        unsigned int rs1 = (insn >> 14) & 0x1f;
        unsigned int rs2 = insn & 0x1f;
index 44db3351691e6c53fbfe9cc68c62e28b5f8247bf..cc857f681d97a49351556efbc85d924fbabea9f1 100644 (file)
@@ -201,6 +201,25 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
        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,
                               unsigned long address)
 {
@@ -307,7 +326,7 @@ bad_area_nosemaphore:
                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 *)address;
+               info.si_addr = (void *) compute_si_addr(regs, text_fault);
                info.si_trapno = 0;
                force_sig_info (SIGSEGV, &info, tsk);
                return;
@@ -361,7 +380,7 @@ do_sigbus:
        info.si_signo = SIGBUS;
        info.si_errno = 0;
        info.si_code = BUS_ADRERR;
-       info.si_addr = (void *)address;
+       info.si_addr = (void *) compute_si_addr(regs, text_fault);
        info.si_trapno = 0;
        force_sig_info (SIGBUS, &info, tsk);
        if (!from_user)
@@ -530,7 +549,7 @@ bad_area:
        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 *)address;
+       info.si_addr = (void *) address;
        info.si_trapno = 0;
        force_sig_info (SIGSEGV, &info, tsk);
        return;
@@ -540,7 +559,7 @@ do_sigbus:
        info.si_signo = SIGBUS;
        info.si_errno = 0;
        info.si_code = BUS_ADRERR;
-       info.si_addr = (void *)address;
+       info.si_addr = (void *) address;
        info.si_trapno = 0;
        force_sig_info (SIGBUS, &info, tsk);
 }
index 5b664354e73bb473637ae57df00163556758641b..646a788fa9d2fa3649eead62fcfcd8283e812b41 100644 (file)
@@ -158,8 +158,8 @@ static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
        }
 }
 
-static unsigned long compute_effective_address(struct pt_regs *regs,
-                                              unsigned int insn, unsigned int rd)
+unsigned long compute_effective_address(struct pt_regs *regs,
+                                       unsigned int insn, unsigned int rd)
 {
        unsigned int rs1 = (insn >> 14) & 0x1f;
        unsigned int rs2 = insn & 0x1f;
index 348f206f0663944b911e8edb52463b04e3f707a4..5fc4644aad99f9697e1ced589a375ceb9e974463 100644 (file)
@@ -207,14 +207,21 @@ outret:
        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;
 
        info.si_code = code;
        info.si_signo = sig;
        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;
        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,
                /* The si_code was set to make clear whether
                 * 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;
        }
 
@@ -471,7 +478,7 @@ do_sigbus:
         * Send a sigbus, regardless of whether we were in kernel
         * 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 */
        if (regs->tstate & TSTATE_PRIV)