Skip to contentSkip to conversation

Advanced Kernel Stack Backtrace

RFC PATCH In review David VomLehn 2 participants 2 messages May 7, 2008 – May 11, 2008 MIPS

lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 Advanced Kernel Stack Backtrace

This patch contains the kernel stack backtrace code we've been running for about a year on our MIPS-based settop box. It is considerably larger than the existing backtrace implementation and so is configurable in the Kernel Hacking section. It also requires that KALLSYMS be enabled. In return, I think it offers some advantages over the existing backtrace code:

o It will backtrace over nested interrupts and exceptions, allowing detailed analysis of was going on when it was invoked.
o It handles a number of corner cases involving instructions in branch delay slots.
o It is very careful to use __get_user when fetching stack data and instructions, meaning that it will fail gracefully even in the presence of stack corruption.
o It identifies whether the $sp register or another register is being used as the frame pointer. Assuming people are happy with this submission, there is a small subsequent patch I'll submit that dumps the frame pointer value as part of the backtrace.
o It segregates the backtrace code into a subdirectory of arch/mips/kernel rather than cluttering up traps.c or the kernel directory.

The main reason I am submitting this as a request for comments rather than as a normal patch is that, though I wrote it with 64-bit systems in mind, I don't have access to a 64-bit system on which to test it. I am happy to merge any 64-bit-specific changes. For 32-bit systems, I'll claim it's ready to go.

The other reason is that this is an RFC is that it is such a large, single chunk of code that there are certainly lots of comments that people will have. I'm not naive enough to think it's really ready without more review.

[Note: for anyone who was at the MIPS backtrace session at the CELF Conference, this is the code I was talking about.]

--

arch/mips/Kconfig.debug +11 -0
diff -urN linux-2.6.25.1/arch/mips/Kconfig.debug linux-t/arch/mips/Kconfig.debug
@@ -73,6 +73,17 @@
 	  include/asm-mips/debug.h for debuging macros.
 	  If unsure, say N.
 
+config MIPS_ADVANCED_BACKTRACE
+	bool "More sophisticated backtrace code"
+	default n
+	depends on KALLSYMS
+	help
+	  Use backtrace code that more completely handles the various
+	  complexities of the MIPS processors, including branch delay
+	  slots. This is substantially larger than the standard backtrace
+	  code. Using this also prints the frame pointer for each function
+	  in the call stack.
+
 config MIPS_UNCACHED
 	bool "Run uncached"
 	depends on DEBUG_KERNEL && !SMP && !SGI_IP27
arch/mips/kernel/backtrace/kernel-backtrace.c renamed from arch/mips/kernel/backtrace/kernel-backtrace.c 1969-12-31 16:00:00.000000000 -0800 +978 -0

978 lines not on this page · raw message

arch/mips/kernel/backtrace/kernel-backtrace-symbols.c 2008-05-06 17:30:09.000000000 -0700 renamed from arch/mips/kernel/backtrace/kernel-backtrace-symbols.c 1969-12-31 16:00:00.000000000 -0800 +44 -0

44 lines not on this page · raw message

arch/mips/kernel/backtrace/Makefile +4 -0
diff -urN linux-2.6.25.1/arch/mips/kernel/backtrace/Makefile linux-t/arch/mips/kernel/backtrace/Makefile
@@ -0,0 +1,4 @@
+# Makefile for Linux/MIPS advanced backtrace code
+
+obj-y	+= kernel-backtrace.o kernel-backtrace-symbols.o \
+	   simple-backtrace.o thread-backtrace.o
arch/mips/kernel/backtrace/simple-backtrace.c renamed from arch/mips/kernel/backtrace/simple-backtrace.c 1969-12-31 16:00:00.000000000 -0800 +1236 -0

1,236 lines not on this page · raw message

arch/mips/kernel/backtrace/thread-backtrace.c renamed from arch/mips/kernel/backtrace/thread-backtrace.c 1969-12-31 16:00:00.000000000 -0800 +388 -0

388 lines not on this page · raw message

arch/mips/kernel/entry.S +7 -0
diff -urN linux-2.6.25.1/arch/mips/kernel/entry.S linux-t/arch/mips/kernel/entry.S
@@ -40,6 +40,7 @@
 	andi	t0, t0, KU_USER
 	beqz	t0, resume_kernel
 
+	.globl	resume_userspace
 resume_userspace:
 	local_irq_disable		# make sure we dont miss an
 					# interrupt setting need_resched
@@ -50,10 +51,12 @@
 	j	restore_all
 
 #ifdef CONFIG_PREEMPT
+	.globl	resume_kernel
 resume_kernel:
 	local_irq_disable
 	lw	t0, TI_PRE_COUNT($28)
 	bnez	t0, restore_all
+	.globl	need_resched
 need_resched:
 	LONG_L	t0, TI_FLAGS($28)
 	andi	t1, t0, _TIF_NEED_RESCHED
@@ -141,9 +144,11 @@
 	RESTORE_SP_AND_RET
 	.set	at
 
+	.globl	work_pending
 work_pending:
 	andi	t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
 	beqz	t0, work_notifysig
+	.globl	work_resched
 work_resched:
 	jal	schedule
 
@@ -157,6 +162,7 @@
 	andi	t0, a2, _TIF_NEED_RESCHED
 	bnez	t0, work_resched
 
+	.globl	work_notifysig
 work_notifysig:				# deal with pending signals and
 					# notify-resume requests
 	move	a0, sp
@@ -166,6 +172,7 @@
 
 FEXPORT(syscall_exit_work_partial)
 	SAVE_STATIC
+	.global	syscall_exit_work
 syscall_exit_work:
 	li	t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
 	and	t0, a2			# a2 is preloaded with TI_FLAGS
arch/mips/kernel/Makefile +1 -1
diff -urN linux-2.6.25.1/arch/mips/kernel/Makefile linux-t/arch/mips/kernel/Makefile
@@ -79,6 +79,7 @@
 
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
+obj-$(CONFIG_MIPS_ADVANCED_BACKTRACE) += backtrace/
 
 CFLAGS_cpu-bugs64.o	= $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c 
-o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
arch/mips/kernel/scall32-o32.S +4 -1
diff -urN linux-2.6.25.1/arch/mips/kernel/scall32-o32.S linux-t/arch/mips/kernel/scall32-o32.S
@@ -54,6 +54,7 @@
 	sw	a3, PT_R26(sp)		# save a3 for syscall restarting
 	bgez	t3, stackargs
 
+	.globl	stack_done
 stack_done:
 	lw	t0, TI_FLAGS($28)	# syscall tracing enabled?
 	li	t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
@@ -72,6 +73,7 @@
 					# restarting
 1:	sw	v0, PT_R2(sp)		# result
 
+	.globl	o32_syscall_exit
 o32_syscall_exit:
 	local_irq_disable		# make sure need_resched and
 					# signals dont change between
@@ -83,11 +85,13 @@
 
 	j	restore_partial
 
+	.globl	o32_syscall_exit_work
 o32_syscall_exit_work:
 	j	syscall_exit_work_partial
 
 /* 
------------------------------------------------------------------------ */
 
+	.globl	syscall_trace_entry
 syscall_trace_entry:
 	SAVE_STATIC

move s0, t2
@@ -122,6 +126,7 @@
* stack arguments from the user stack to the kernel stack.
* This Sucks (TM).
*/
+ .globl stackargs
stackargs:
lw t0, PT_R29(sp) # get old user stack pointer

@@ -132,7 +137,7 @@
lw t5, TI_ADDR_LIMIT($28)
addu t4, t0, 32
and t5, t4
- bltz t5, bad_stack # -> sp is bad
+ bltz t5, _bad_stack # -> sp is bad

/* Ok, copy the args from the luser stack to the kernel stack.
* t3 is the precomputed number of instruction bytes needed to
@@ -162,17 +167,18 @@
.set pop

.section __ex_table,"a"
- PTR 1b,bad_stack
- PTR 2b,bad_stack
- PTR 3b,bad_stack
- PTR 4b,bad_stack
+ PTR 1b,_bad_stack
+ PTR 2b,_bad_stack
+ PTR 3b,_bad_stack
+ PTR 4b,_bad_stack
.previous

/*
* The stackpointer for a call with more than 4 arguments is bad.
* We probably should handle this case a bit more drastic. */
-bad_stack:
+ .globl _bad_stack
+_bad_stack:
negu v0 # error
sw v0, PT_R0(sp)
sw v0, PT_R2(sp)
@@ -183,6 +189,7 @@
/*
* The system call does not exist in this kernel
*/
+ .globl illegal_syscall
illegal_syscall:
li v0, -ENOSYS # error
sw v0, PT_R2(sp)
@@ -213,8 +220,8 @@
#endif

.section __ex_table,"a"
- PTR 1b, bad_stack
- PTR 2b, bad_stack
+ PTR 1b, _bad_stack
+ PTR 2b, _bad_stack
.previous
#else
sw a1, 16(sp)
@@ -246,13 +253,16 @@

j o32_syscall_exit # continue like a normal syscall

+ .globl no_mem
no_mem: li v0, -ENOMEM
jr ra

+ .globl bad_address
bad_address:
li v0, -EFAULT
jr ra

+ .globl bad_alignment
bad_alignment:
li v0, -EINVAL
jr ra
@@ -305,6 +315,7 @@
jr t2
/* Unreached */

+ .globl einval
einval: li v0, -EINVAL
jr ra
END(sys_syscall)

arch/mips/kernel/signal32.c +1 -7
diff -urN linux-2.6.25.1/arch/mips/kernel/signal32.c linux-t/arch/mips/kernel/signal32.c
@@ -32,16 +32,10 @@
 #include <asm/system.h>
 #include <asm/fpu.h>
 #include <asm/war.h>
+#include <asm/sigframe.h>
 
 #include "signal-common.h"
 
-/*
- * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
- */
-#define __NR_O32_sigreturn		4119
-#define __NR_O32_rt_sigreturn		4193
-#define __NR_O32_restart_syscall        4253
-
 /* 32-bit compatibility types */
 
 typedef unsigned int __sighandler32_t;
arch/mips/kernel/signal.c +1 -41

52 lines not on this page · raw message

arch/mips/kernel/traps.c +69 -6

96 lines not on this page · raw message

include/asm-mips/kernel-backtrace.h +81 -0

81 lines not on this page · raw message

include/asm-mips/kernel-backtrace-symbols.h renamed from include/asm-mips/kernel-backtrace-symbols.h 1969-12-31 16:00:00.000000000 -0800 +133 -0

9 lines not on this page · raw message

include/asm-mips/ptrace.h +12 -0
diff -urN linux-2.6.25.1/include/asm-mips/ptrace.h linux-t/include/asm-mips/ptrace.h

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

during a
* system call/exception. As usual the registers k0/k1 aren't being saved.
@@ -34,7 +46,7 @@
#endif

/* Saved main processor registers. */
- unsigned long regs[32];
+ unsigned long regs[REG_ALL];

/* Saved special registers. */
unsigned long cp0_status;

include/asm-mips/sigframe.h +73 -0

73 lines not on this page · raw message

include/asm-mips/simple-backtrace.h +344 -0

344 lines not on this page · raw message

include/asm-mips/stacktrace.h +39 -8

47 lines not on this page · raw message

include/asm-mips/thread-backtrace.h +229 -0

229 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#1 lore raw
Quoted 26 lines · David VomLehn

This patch contains the kernel stack backtrace code we've been running for about a year on our MIPS-based settop box. It is considerably larger than the existing backtrace implementation and so is configurable in the Kernel Hacking section. It also requires that KALLSYMS be enabled. In return, I think it offers some advantages over the existing backtrace code:

o It will backtrace over nested interrupts and exceptions, allowing detailed analysis of was going on when it was invoked.
o It handles a number of corner cases involving instructions in branch delay slots.
o It is very careful to use __get_user when fetching stack data and instructions, meaning that it will fail gracefully even in the presence of stack corruption.
o It identifies whether the $sp register or another register is being used as the frame pointer. Assuming people are happy with this submission, there is a small subsequent patch I'll submit that dumps the frame pointer value as part of the backtrace.
o It segregates the backtrace code into a subdirectory of arch/mips/kernel rather than cluttering up traps.c or the kernel directory.

The main reason I am submitting this as a request for comments rather than as a normal patch is that, though I wrote it with 64-bit systems in mind, I don't have access to a 64-bit system on which to test it. I am happy to merge any 64-bit-specific changes. For 32-bit systems, I'll claim it's ready to go.

Quoted 6 lines

The other reason is that this is an RFC is that it is such a large, single chunk of code that there are certainly lots of comments that people will have. I'm not naive enough to think it's really ready without more review.

[Note: for anyone who was at the MIPS backtrace session at the CELF Conference, this is the code I was talking about.]

I wasn't even aware of the session.

arch/mips/kernel/backtrace/kernel-backtrace.c line 39

Quoted 5 lines
arch/mips/kernel/backtrace/kernel-backtrace.c renamed from arch/mips/kernel/backtrace/kernel-backtrace.c 1969-12-31 16:00:00.000000000 -0800 +3 -0
+#ifndef	numberof
+#define	numberof(a)	(sizeof(a) / sizeof((a) [0]))
+#endif

I really just glanced over the patch. I think I like the promise of more accurate backtraces because frequently one (1) backtrace is all information which there ever will be available for debugging.

o Use ARRAY_SIZE() from <linux/kernel.h> instead of numberof.
o Please run the patch through scripts/checkpatch.pl and fix the resulting errors.
o Your patch got linewrapped by your mail client.

Ralf