Exception trace for i386
diff mbox series

Message ID 20030519192814.GA975@averell
State New, archived
Headers show
Series
  • Exception trace for i386
Related show

Commit Message

Andi Kleen May 19, 2003, 7:28 p.m. UTC
x86-64 had printks for user level faults for a long time. This
proved to be very useful to trace otherwise hidden faults, e.g.
on a normal kernel there is no way to see a segfault in a process
that runs in a write protected directory, even when core dumps
are enabled. Also it's useful as an early warning that something
is wrong with your system.

There was a request to port this to i386. Done with this patch.

It is turned off by default because some programs do deliberate
segfaults (e.g. lmbench), but can be enabled with a sysctl.
int 3s are not logged because they are used gdb and debugging
becomes too noisy otherwise.

As a intended side effect this also exposes the hidden exception_trace 
variable that already exists in arch/x86_64 as sysctl.

Patch for 2.5.69-CVS

-Andi

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Comments

Linus Torvalds May 19, 2003, 8:56 p.m. UTC | #1
In article <20030519192814.GA975@averell>, Andi Kleen  <ak@muc.de> wrote:
>
>x86-64 had printks for user level faults for a long time. This
>proved to be very useful to trace otherwise hidden faults, e.g.
>on a normal kernel there is no way to see a segfault in a process
>that runs in a write protected directory, even when core dumps
>are enabled. Also it's useful as an early warning that something
>is wrong with your system.
>
>There was a request to port this to i386. Done with this patch.

Please don't do it this way. For one thing, there are valid uses where
you want to enable tracing for just one process. For another, there are
actually cases where you may want to trace all page faults, even the
ones that don't cause signals - kind of like normal system calls. After
all, from a behavioural standpoint, that is what they are: implied
system calls.

So I think you want to make it per-process, and expose it as a ptrace
thing (imaging seeing all the page faults a process is taking with
"strace". Potentially quite useful for performance tuning).

I don't think it's ever really valid to expose it as a global option, as
some programs use page faults (even the signalling kind) to do their own
memory management, and making it a global option just makes it hard to
work with such programs.

		Linus
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Alan Cox May 19, 2003, 10:24 p.m. UTC | #2
On Llu, 2003-05-19 at 21:56, Linus Torvalds wrote:
> >proved to be very useful to trace otherwise hidden faults, e.g.
> >on a normal kernel there is no way to see a segfault in a process
> >that runs in a write protected directory, even when core dumps
> >are enabled. Also it's useful as an early warning that something
> >is wrong with your system.

You can change the segfault path for core dumps via /proc 

> I don't think it's ever really valid to expose it as a global option, as
> some programs use page faults (even the signalling kind) to do their own
> memory management, and making it a global option just makes it hard to
> work with such programs.

The classic being the texas objectstore which I suspect would not be
happy if printk logged each fault 8)

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Patch
diff mbox series

Index: linux/arch/i386/kernel/traps.c
===================================================================
RCS file: /home/cvs/linux-2.5/arch/i386/kernel/traps.c,v
retrieving revision 1.54
diff -u -u -r1.54 traps.c
--- linux/arch/i386/kernel/traps.c	13 May 2003 02:56:54 -0000	1.54
+++ linux/arch/i386/kernel/traps.c	19 May 2003 18:19:33 -0000
@@ -53,6 +53,8 @@ 
 
 #include "mach_traps.h"
 
+extern int exception_trace;
+
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
 asmlinkage void lcall27(void);
@@ -303,6 +305,11 @@ 
 
 	trap_signal: {
 		struct task_struct *tsk = current;
+
+		if (exception_trace && trapnr != 3)
+			printk(KERN_INFO "%s[%d] trap %s at eip:%lx esp:%lx err:%lx\n",
+		       tsk->comm, tsk->pid, str, regs->eip, regs->esp, error_code);
+
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = trapnr;
 		if (info)
@@ -372,15 +379,20 @@ 
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
+	struct task_struct *tsk = current;
 	if (regs->eflags & VM_MASK)
 		goto gp_in_vm86;
 
 	if (!(regs->xcs & 3))
 		goto gp_in_kernel;
 
-	current->thread.error_code = error_code;
-	current->thread.trap_no = 13;
-	force_sig(SIGSEGV, current);
+	if (exception_trace)
+		printk(KERN_INFO "%s[%d] gpf at eip:%lx esp:%lx err:%lx\n",
+		       tsk->comm, tsk->pid, regs->eip, regs->esp, error_code);
+	
+	tsk->thread.error_code = error_code;
+	tsk->thread.trap_no = 13;
+	force_sig(SIGSEGV, tsk);
 	return;
 
 gp_in_vm86:
Index: linux/arch/i386/mm/fault.c
===================================================================
RCS file: /home/cvs/linux-2.5/arch/i386/mm/fault.c,v
retrieving revision 1.27
diff -u -u -r1.27 fault.c
--- linux/arch/i386/mm/fault.c	8 May 2003 05:19:20 -0000	1.27
+++ linux/arch/i386/mm/fault.c	19 May 2003 18:19:33 -0000
@@ -57,6 +57,8 @@ 
 
 asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
 
+int exception_trace;
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -200,6 +202,13 @@ 
 
 	/* User mode accesses just cause a SIGSEGV */
 	if (error_code & 4) {
+
+		if (exception_trace)
+			printk(KERN_INFO 
+		       "%s[%d] segfault at eip:%lx esp:%lx adr:%lx err:%lx\n",
+		       tsk->comm, tsk->pid, regs->eip, regs->esp, address, 
+		       error_code);
+
 		tsk->thread.cr2 = address;
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = 14;
Index: linux/include/linux/sysctl.h
===================================================================
RCS file: /home/cvs/linux-2.5/include/linux/sysctl.h,v
retrieving revision 1.43
diff -u -u -r1.43 sysctl.h
--- linux/include/linux/sysctl.h	12 May 2003 18:25:53 -0000	1.43
+++ linux/include/linux/sysctl.h	19 May 2003 18:19:38 -0000
@@ -130,6 +130,7 @@ 
 	KERN_PIDMAX=55,		/* int: PID # limit */
   	KERN_CORE_PATTERN=56,	/* string: pattern for core-file names */
 	KERN_PANIC_ON_OOPS=57,  /* int: whether we will panic on an oops */
+	KERN_EXCEPTION_TRACE=58, /* int: log user traps in kernel log */
 };
 
 
Index: linux/kernel/sysctl.c
===================================================================
RCS file: /home/cvs/linux-2.5/kernel/sysctl.c,v
retrieving revision 1.42
diff -u -u -r1.42 sysctl.c
--- linux/kernel/sysctl.c	12 May 2003 18:25:53 -0000	1.42
+++ linux/kernel/sysctl.c	19 May 2003 18:19:39 -0000
@@ -57,6 +57,7 @@ 
 extern int cad_pid;
 extern int pid_max;
 extern int sysctl_lower_zone_protection;
+extern int exception_trace;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -265,6 +266,10 @@ 
 	 0600, NULL, &proc_dointvec},
 	{KERN_PANIC_ON_OOPS,"panic_on_oops",
 	 &panic_on_oops,sizeof(int),0644,NULL,&proc_dointvec},
+#ifdef CONFIG_X86
+	{KERN_EXCEPTION_TRACE,"exception_trace",
+	 &exception_trace,sizeof(int),0644,NULL,&proc_dointvec},
+#endif
 	{0}
 };