Advanced Kernel Stack Backtrace
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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.
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_userwhen 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 ofarch/mips/kernelrather than cluttering uptraps.cor 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
Signed-off-by David VomLehn <[email protected]>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