Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ab3c68ee authored by Heiko Carstens's avatar Heiko Carstens Committed by Martin Schwidefsky
Browse files

[S390] debug: enable exception-trace debug facility



The exception-trace facility on x86 and other architectures prints
traces to dmesg whenever a user space application crashes.
s390 has such a feature since ages however it is called
userprocess_debug and is enabled differently.
This patch makes sure that whenever one of the two procfs files

/proc/sys/kernel/userprocess_debug
/proc/sys/debug/exception-trace

is modified the contents of the second one changes as well.
That way we keep backwards compatibilty but also support the same
interface like other architectures do.
Besides that the output of the traces is improved since it will now
also contain the corresponding filename of the vma (when available)
where the process caused a fault or trap.

Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 57b28f66
Loading
Loading
Loading
Loading
+0 −7
Original line number Original line Diff line number Diff line
@@ -444,13 +444,6 @@ config FORCE_MAX_ZONEORDER
	int
	int
	default "9"
	default "9"


config PROCESS_DEBUG
	bool "Show crashed user process info"
	help
	  Say Y to print all process fault locations to the console.  This is
	  a debugging option; you probably do not want to set it unless you
	  are an S390 port maintainer.

config PFAULT
config PFAULT
	bool "Pseudo page fault support"
	bool "Pseudo page fault support"
	help
	help
+13 −18
Original line number Original line Diff line number Diff line
@@ -46,13 +46,7 @@


pgm_check_handler_t *pgm_check_table[128];
pgm_check_handler_t *pgm_check_table[128];


#ifdef CONFIG_SYSCTL
int show_unhandled_signals;
#ifdef CONFIG_PROCESS_DEBUG
int sysctl_userprocess_debug = 1;
#else
int sysctl_userprocess_debug = 0;
#endif
#endif


extern pgm_check_handler_t do_protection_exception;
extern pgm_check_handler_t do_protection_exception;
extern pgm_check_handler_t do_dat_exception;
extern pgm_check_handler_t do_dat_exception;
@@ -315,18 +309,19 @@ void die(const char * str, struct pt_regs * regs, long err)
	do_exit(SIGSEGV);
	do_exit(SIGSEGV);
}
}


static void inline
static void inline report_user_fault(struct pt_regs *regs, long int_code,
report_user_fault(long interruption_code, struct pt_regs *regs)
				     int signr)
{
{
#if defined(CONFIG_SYSCTL)
	if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
	if (!sysctl_userprocess_debug)
		return;
		return;
#endif
	if (!unhandled_signal(current, signr))
#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
		return;
	printk("User process fault: interruption code 0x%lX\n",
	if (!printk_ratelimit())
	       interruption_code);
		return;
	printk("User process fault: interruption code 0x%lX ", int_code);
	print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN);
	printk("\n");
	show_regs(regs);
	show_regs(regs);
#endif
}
}


int is_valid_bugaddr(unsigned long addr)
int is_valid_bugaddr(unsigned long addr)
@@ -354,7 +349,7 @@ static void __kprobes inline do_trap(long interruption_code, int signr,


                tsk->thread.trap_no = interruption_code & 0xffff;
                tsk->thread.trap_no = interruption_code & 0xffff;
		force_sig_info(signr, info, tsk);
		force_sig_info(signr, info, tsk);
		report_user_fault(interruption_code, regs);
		report_user_fault(regs, interruption_code, signr);
        } else {
        } else {
                const struct exception_table_entry *fixup;
                const struct exception_table_entry *fixup;
                fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
                fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
@@ -390,7 +385,7 @@ static void default_trap_handler(struct pt_regs * regs, long interruption_code)
{
{
        if (regs->psw.mask & PSW_MASK_PSTATE) {
        if (regs->psw.mask & PSW_MASK_PSTATE) {
		local_irq_enable();
		local_irq_enable();
		report_user_fault(interruption_code, regs);
		report_user_fault(regs, interruption_code, SIGSEGV);
		do_exit(SIGSEGV);
		do_exit(SIGSEGV);
	} else
	} else
		die("Unknown program exception", regs, interruption_code);
		die("Unknown program exception", regs, interruption_code);
+17 −15
Original line number Original line Diff line number Diff line
@@ -48,10 +48,6 @@
#define __PF_RES_FIELD 0x8000000000000000ULL
#define __PF_RES_FIELD 0x8000000000000000ULL
#endif /* CONFIG_64BIT */
#endif /* CONFIG_64BIT */


#ifdef CONFIG_SYSCTL
extern int sysctl_userprocess_debug;
#endif

#define VM_FAULT_BADCONTEXT	0x010000
#define VM_FAULT_BADCONTEXT	0x010000
#define VM_FAULT_BADMAP		0x020000
#define VM_FAULT_BADMAP		0x020000
#define VM_FAULT_BADACCESS	0x040000
#define VM_FAULT_BADACCESS	0x040000
@@ -120,6 +116,22 @@ static inline int user_space_fault(unsigned long trans_exc_code)
	return trans_exc_code != 3;
	return trans_exc_code != 3;
}
}


static inline void report_user_fault(struct pt_regs *regs, long int_code,
				     int signr, unsigned long address)
{
	if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
		return;
	if (!unhandled_signal(current, signr))
		return;
	if (!printk_ratelimit())
		return;
	printk("User process fault: interruption code 0x%lX ", int_code);
	print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN);
	printk("\n");
	printk("failing address: %lX\n", address);
	show_regs(regs);
}

/*
/*
 * Send SIGSEGV to task.  This is an external routine
 * Send SIGSEGV to task.  This is an external routine
 * to keep the stack usage of do_page_fault small.
 * to keep the stack usage of do_page_fault small.
@@ -133,17 +145,7 @@ static noinline void do_sigsegv(struct pt_regs *regs, long int_code,
	address = trans_exc_code & __FAIL_ADDR_MASK;
	address = trans_exc_code & __FAIL_ADDR_MASK;
	current->thread.prot_addr = address;
	current->thread.prot_addr = address;
	current->thread.trap_no = int_code;
	current->thread.trap_no = int_code;
#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
	report_user_fault(regs, int_code, SIGSEGV, address);
#if defined(CONFIG_SYSCTL)
	if (sysctl_userprocess_debug)
#endif
	{
		printk("User process fault: interruption code 0x%lX\n",
		       int_code);
		printk("failing address: %lX\n", address);
		show_regs(regs);
	}
#endif
	si.si_signo = SIGSEGV;
	si.si_signo = SIGSEGV;
	si.si_code = si_code;
	si.si_code = si_code;
	si.si_addr = (void __user *) address;
	si.si_addr = (void __user *) address;
+3 −2
Original line number Original line Diff line number Diff line
@@ -621,7 +621,7 @@ static struct ctl_table kern_table[] = {
#endif
#endif
	{
	{
		.procname	= "userprocess_debug",
		.procname	= "userprocess_debug",
		.data		= &sysctl_userprocess_debug,
		.data		= &show_unhandled_signals,
		.maxlen		= sizeof(int),
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.mode		= 0644,
		.proc_handler	= proc_dointvec,
		.proc_handler	= proc_dointvec,
@@ -1431,7 +1431,8 @@ 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) || defined(CONFIG_SPARC)
#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || \
    defined(CONFIG_S390)
	{
	{
		.procname	= "exception-trace",
		.procname	= "exception-trace",
		.data		= &show_unhandled_signals,
		.data		= &show_unhandled_signals,