Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: mm: Add debug information for userland SIGSEGV signals.

Commit 41c594ab65fc ("[MIPS] MT: Improved multithreading support.")
removed useful debug information for userland segmentation faults.
This patch bring this back along with the ability to determine the
name of the object file where the EPC and RA registers point at.
Furthermore, we select the SYSCTL_EXCEPTION_TRACE symbol for MIPS
which is the de facto solution to turn userland exception logging
on and off via the /proc/sys/debug/exception-trace file.

Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Cc: James Hogan <james.hogan@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/9089/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Markos Chandras and committed by
Ralf Baechle
d79d853d 9791554b

+21 -9
+1
arch/mips/Kconfig
··· 54 54 select CPU_PM if CPU_IDLE 55 55 select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST 56 56 select ARCH_BINFMT_ELF_STATE 57 + select SYSCTL_EXCEPTION_TRACE 57 58 58 59 menu "Machine selection" 59 60
+20 -9
arch/mips/mm/fault.c
··· 14 14 #include <linux/string.h> 15 15 #include <linux/types.h> 16 16 #include <linux/ptrace.h> 17 + #include <linux/ratelimit.h> 17 18 #include <linux/mman.h> 18 19 #include <linux/mm.h> 19 20 #include <linux/smp.h> ··· 28 27 #include <asm/ptrace.h> 29 28 #include <asm/highmem.h> /* For VMALLOC_END */ 30 29 #include <linux/kdebug.h> 30 + 31 + int show_unhandled_signals = 1; 31 32 32 33 /* 33 34 * This routine handles page faults. It determines the address, ··· 46 43 siginfo_t info; 47 44 int fault; 48 45 unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; 46 + 47 + static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10); 49 48 50 49 #if 0 51 50 printk("Cpu%d[%s:%d:%0*lx:%ld:%0*lx]\n", raw_smp_processor_id(), ··· 206 201 if (user_mode(regs)) { 207 202 tsk->thread.cp0_badvaddr = address; 208 203 tsk->thread.error_code = write; 209 - #if 0 210 - printk("do_page_fault() #2: sending SIGSEGV to %s for " 211 - "invalid %s\n%0*lx (epc == %0*lx, ra == %0*lx)\n", 212 - tsk->comm, 213 - write ? "write access to" : "read access from", 214 - field, address, 215 - field, (unsigned long) regs->cp0_epc, 216 - field, (unsigned long) regs->regs[31]); 217 - #endif 204 + if (show_unhandled_signals && 205 + unhandled_signal(tsk, SIGSEGV) && 206 + __ratelimit(&ratelimit_state)) { 207 + pr_info("\ndo_page_fault(): sending SIGSEGV to %s for invalid %s %0*lx", 208 + tsk->comm, 209 + write ? "write access to" : "read access from", 210 + field, address); 211 + pr_info("epc = %0*lx in", field, 212 + (unsigned long) regs->cp0_epc); 213 + print_vma_addr(" ", regs->cp0_epc); 214 + pr_info("ra = %0*lx in", field, 215 + (unsigned long) regs->regs[31]); 216 + print_vma_addr(" ", regs->regs[31]); 217 + pr_info("\n"); 218 + } 218 219 info.si_signo = SIGSEGV; 219 220 info.si_errno = 0; 220 221 /* info.si_code has been set above */