Remove stack unwinder for now
It has caused more problems than it ever really solved, and is apparently not getting cleaned up and fixed. We can put it back when it's stable and isn't likely to make warning or bug events worse. In the meantime, enable frame pointers for more readable stack traces. Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
d1998ef38a
commit
d1526e2cda
5
Makefile
5
Makefile
@ -496,11 +496,6 @@ else
|
||||
CFLAGS += -fomit-frame-pointer
|
||||
endif
|
||||
|
||||
ifdef CONFIG_UNWIND_INFO
|
||||
CFLAGS += -fasynchronous-unwind-tables
|
||||
LDFLAGS_vmlinux += --eh-frame-hdr
|
||||
endif
|
||||
|
||||
ifdef CONFIG_DEBUG_INFO
|
||||
CFLAGS += -g
|
||||
endif
|
||||
|
@ -1493,8 +1493,6 @@ CONFIG_DEBUG_BUGVERBOSE=y
|
||||
# CONFIG_DEBUG_VM is not set
|
||||
# CONFIG_DEBUG_LIST is not set
|
||||
# CONFIG_FRAME_POINTER is not set
|
||||
CONFIG_UNWIND_INFO=y
|
||||
CONFIG_STACK_UNWIND=y
|
||||
# CONFIG_FORCED_INLINING is not set
|
||||
# CONFIG_HEADERS_CHECK is not set
|
||||
# CONFIG_RCU_TORTURE_TEST is not set
|
||||
|
@ -979,38 +979,6 @@ ENTRY(spurious_interrupt_bug)
|
||||
jmp error_code
|
||||
CFI_ENDPROC
|
||||
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
ENTRY(arch_unwind_init_running)
|
||||
CFI_STARTPROC
|
||||
movl 4(%esp), %edx
|
||||
movl (%esp), %ecx
|
||||
leal 4(%esp), %eax
|
||||
movl %ebx, PT_EBX(%edx)
|
||||
xorl %ebx, %ebx
|
||||
movl %ebx, PT_ECX(%edx)
|
||||
movl %ebx, PT_EDX(%edx)
|
||||
movl %esi, PT_ESI(%edx)
|
||||
movl %edi, PT_EDI(%edx)
|
||||
movl %ebp, PT_EBP(%edx)
|
||||
movl %ebx, PT_EAX(%edx)
|
||||
movl $__USER_DS, PT_DS(%edx)
|
||||
movl $__USER_DS, PT_ES(%edx)
|
||||
movl $0, PT_GS(%edx)
|
||||
movl %ebx, PT_ORIG_EAX(%edx)
|
||||
movl %ecx, PT_EIP(%edx)
|
||||
movl 12(%esp), %ecx
|
||||
movl $__KERNEL_CS, PT_CS(%edx)
|
||||
movl %ebx, PT_EFLAGS(%edx)
|
||||
movl %eax, PT_OLDESP(%edx)
|
||||
movl 8(%esp), %eax
|
||||
movl %ecx, 8(%esp)
|
||||
movl PT_EBX(%edx), %ebx
|
||||
movl $__KERNEL_DS, PT_OLDSS(%edx)
|
||||
jmpl *%eax
|
||||
CFI_ENDPROC
|
||||
ENDPROC(arch_unwind_init_running)
|
||||
#endif
|
||||
|
||||
ENTRY(kernel_thread_helper)
|
||||
pushl $0 # fake return address for unwinder
|
||||
CFI_STARTPROC
|
||||
|
@ -94,11 +94,6 @@ asmlinkage void spurious_interrupt_bug(void);
|
||||
asmlinkage void machine_check(void);
|
||||
|
||||
int kstack_depth_to_print = 24;
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
static int call_trace = 1;
|
||||
#else
|
||||
#define call_trace (-1)
|
||||
#endif
|
||||
ATOMIC_NOTIFIER_HEAD(i386die_chain);
|
||||
|
||||
int register_die_notifier(struct notifier_block *nb)
|
||||
@ -152,33 +147,6 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,
|
||||
return ebp;
|
||||
}
|
||||
|
||||
struct ops_and_data {
|
||||
struct stacktrace_ops *ops;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static asmlinkage int
|
||||
dump_trace_unwind(struct unwind_frame_info *info, void *data)
|
||||
{
|
||||
struct ops_and_data *oad = (struct ops_and_data *)data;
|
||||
int n = 0;
|
||||
unsigned long sp = UNW_SP(info);
|
||||
|
||||
if (arch_unw_user_mode(info))
|
||||
return -1;
|
||||
while (unwind(info) == 0 && UNW_PC(info)) {
|
||||
n++;
|
||||
oad->ops->address(oad->data, UNW_PC(info));
|
||||
if (arch_unw_user_mode(info))
|
||||
break;
|
||||
if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1))
|
||||
&& sp > UNW_SP(info))
|
||||
break;
|
||||
sp = UNW_SP(info);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#define MSG(msg) ops->warning(data, msg)
|
||||
|
||||
void dump_trace(struct task_struct *task, struct pt_regs *regs,
|
||||
@ -190,41 +158,6 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
|
||||
if (!task)
|
||||
task = current;
|
||||
|
||||
if (call_trace >= 0) {
|
||||
int unw_ret = 0;
|
||||
struct unwind_frame_info info;
|
||||
struct ops_and_data oad = { .ops = ops, .data = data };
|
||||
|
||||
if (regs) {
|
||||
if (unwind_init_frame_info(&info, task, regs) == 0)
|
||||
unw_ret = dump_trace_unwind(&info, &oad);
|
||||
} else if (task == current)
|
||||
unw_ret = unwind_init_running(&info, dump_trace_unwind,
|
||||
&oad);
|
||||
else {
|
||||
if (unwind_init_blocked(&info, task) == 0)
|
||||
unw_ret = dump_trace_unwind(&info, &oad);
|
||||
}
|
||||
if (unw_ret > 0) {
|
||||
if (call_trace == 1 && !arch_unw_user_mode(&info)) {
|
||||
ops->warning_symbol(data,
|
||||
"DWARF2 unwinder stuck at %s",
|
||||
UNW_PC(&info));
|
||||
if (UNW_SP(&info) >= PAGE_OFFSET) {
|
||||
MSG("Leftover inexact backtrace:");
|
||||
stack = (void *)UNW_SP(&info);
|
||||
if (!stack)
|
||||
return;
|
||||
ebp = UNW_FP(&info);
|
||||
} else
|
||||
MSG("Full inexact backtrace again:");
|
||||
} else if (call_trace >= 1)
|
||||
return;
|
||||
else
|
||||
MSG("Full inexact backtrace again:");
|
||||
} else
|
||||
MSG("Inexact backtrace:");
|
||||
}
|
||||
if (!stack) {
|
||||
unsigned long dummy;
|
||||
stack = &dummy;
|
||||
@ -1258,19 +1191,3 @@ static int __init kstack_setup(char *s)
|
||||
return 1;
|
||||
}
|
||||
__setup("kstack=", kstack_setup);
|
||||
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
static int __init call_trace_setup(char *s)
|
||||
{
|
||||
if (strcmp(s, "old") == 0)
|
||||
call_trace = -1;
|
||||
else if (strcmp(s, "both") == 0)
|
||||
call_trace = 0;
|
||||
else if (strcmp(s, "newfallback") == 0)
|
||||
call_trace = 1;
|
||||
else if (strcmp(s, "new") == 2)
|
||||
call_trace = 2;
|
||||
return 1;
|
||||
}
|
||||
__setup("call_trace=", call_trace_setup);
|
||||
#endif
|
||||
|
@ -45,9 +45,7 @@ cflags-kernel-$(CONFIG_REORDER) += -ffunction-sections
|
||||
# actually it makes the kernel smaller too.
|
||||
cflags-y += -fno-reorder-blocks
|
||||
cflags-y += -Wno-sign-compare
|
||||
ifneq ($(CONFIG_UNWIND_INFO),y)
|
||||
cflags-y += -fno-asynchronous-unwind-tables
|
||||
endif
|
||||
ifneq ($(CONFIG_DEBUG_INFO),y)
|
||||
# -fweb shrinks the kernel a bit, but the difference is very small
|
||||
# it also messes up debugging, so don't use it for now.
|
||||
|
@ -1523,8 +1523,6 @@ CONFIG_DEBUG_FS=y
|
||||
# CONFIG_DEBUG_VM is not set
|
||||
# CONFIG_DEBUG_LIST is not set
|
||||
# CONFIG_FRAME_POINTER is not set
|
||||
CONFIG_UNWIND_INFO=y
|
||||
CONFIG_STACK_UNWIND=y
|
||||
# CONFIG_FORCED_INLINING is not set
|
||||
# CONFIG_HEADERS_CHECK is not set
|
||||
# CONFIG_RCU_TORTURE_TEST is not set
|
||||
|
@ -1155,36 +1155,3 @@ ENTRY(call_softirq)
|
||||
ret
|
||||
CFI_ENDPROC
|
||||
ENDPROC(call_softirq)
|
||||
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
ENTRY(arch_unwind_init_running)
|
||||
CFI_STARTPROC
|
||||
movq %r15, R15(%rdi)
|
||||
movq %r14, R14(%rdi)
|
||||
xchgq %rsi, %rdx
|
||||
movq %r13, R13(%rdi)
|
||||
movq %r12, R12(%rdi)
|
||||
xorl %eax, %eax
|
||||
movq %rbp, RBP(%rdi)
|
||||
movq %rbx, RBX(%rdi)
|
||||
movq (%rsp), %rcx
|
||||
movq %rax, R11(%rdi)
|
||||
movq %rax, R10(%rdi)
|
||||
movq %rax, R9(%rdi)
|
||||
movq %rax, R8(%rdi)
|
||||
movq %rax, RAX(%rdi)
|
||||
movq %rax, RCX(%rdi)
|
||||
movq %rax, RDX(%rdi)
|
||||
movq %rax, RSI(%rdi)
|
||||
movq %rax, RDI(%rdi)
|
||||
movq %rax, ORIG_RAX(%rdi)
|
||||
movq %rcx, RIP(%rdi)
|
||||
leaq 8(%rsp), %rcx
|
||||
movq $__KERNEL_CS, CS(%rdi)
|
||||
movq %rax, EFLAGS(%rdi)
|
||||
movq %rcx, RSP(%rdi)
|
||||
movq $__KERNEL_DS, SS(%rdi)
|
||||
jmpq *%rdx
|
||||
CFI_ENDPROC
|
||||
ENDPROC(arch_unwind_init_running)
|
||||
#endif
|
||||
|
@ -110,11 +110,6 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
|
||||
}
|
||||
|
||||
int kstack_depth_to_print = 12;
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
static int call_trace = 1;
|
||||
#else
|
||||
#define call_trace (-1)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
void printk_address(unsigned long address)
|
||||
@ -217,32 +212,6 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ops_and_data {
|
||||
struct stacktrace_ops *ops;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static int dump_trace_unwind(struct unwind_frame_info *info, void *context)
|
||||
{
|
||||
struct ops_and_data *oad = (struct ops_and_data *)context;
|
||||
int n = 0;
|
||||
unsigned long sp = UNW_SP(info);
|
||||
|
||||
if (arch_unw_user_mode(info))
|
||||
return -1;
|
||||
while (unwind(info) == 0 && UNW_PC(info)) {
|
||||
n++;
|
||||
oad->ops->address(oad->data, UNW_PC(info));
|
||||
if (arch_unw_user_mode(info))
|
||||
break;
|
||||
if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1))
|
||||
&& sp > UNW_SP(info))
|
||||
break;
|
||||
sp = UNW_SP(info);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#define MSG(txt) ops->warning(data, txt)
|
||||
|
||||
/*
|
||||
@ -270,40 +239,6 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
|
||||
if (!tsk)
|
||||
tsk = current;
|
||||
|
||||
if (call_trace >= 0) {
|
||||
int unw_ret = 0;
|
||||
struct unwind_frame_info info;
|
||||
struct ops_and_data oad = { .ops = ops, .data = data };
|
||||
|
||||
if (regs) {
|
||||
if (unwind_init_frame_info(&info, tsk, regs) == 0)
|
||||
unw_ret = dump_trace_unwind(&info, &oad);
|
||||
} else if (tsk == current)
|
||||
unw_ret = unwind_init_running(&info, dump_trace_unwind,
|
||||
&oad);
|
||||
else {
|
||||
if (unwind_init_blocked(&info, tsk) == 0)
|
||||
unw_ret = dump_trace_unwind(&info, &oad);
|
||||
}
|
||||
if (unw_ret > 0) {
|
||||
if (call_trace == 1 && !arch_unw_user_mode(&info)) {
|
||||
ops->warning_symbol(data,
|
||||
"DWARF2 unwinder stuck at %s",
|
||||
UNW_PC(&info));
|
||||
if ((long)UNW_SP(&info) < 0) {
|
||||
MSG("Leftover inexact backtrace:");
|
||||
stack = (unsigned long *)UNW_SP(&info);
|
||||
if (!stack)
|
||||
goto out;
|
||||
} else
|
||||
MSG("Full inexact backtrace again:");
|
||||
} else if (call_trace >= 1)
|
||||
goto out;
|
||||
else
|
||||
MSG("Full inexact backtrace again:");
|
||||
} else
|
||||
MSG("Inexact backtrace:");
|
||||
}
|
||||
if (!stack) {
|
||||
unsigned long dummy;
|
||||
stack = &dummy;
|
||||
@ -387,7 +322,6 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
|
||||
tinfo = current_thread_info();
|
||||
HANDLE_STACK (valid_stack_ptr(tinfo, stack));
|
||||
#undef HANDLE_STACK
|
||||
out:
|
||||
put_cpu();
|
||||
}
|
||||
EXPORT_SYMBOL(dump_trace);
|
||||
@ -1188,21 +1122,3 @@ static int __init kstack_setup(char *s)
|
||||
return 0;
|
||||
}
|
||||
early_param("kstack", kstack_setup);
|
||||
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
static int __init call_trace_setup(char *s)
|
||||
{
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
if (strcmp(s, "old") == 0)
|
||||
call_trace = -1;
|
||||
else if (strcmp(s, "both") == 0)
|
||||
call_trace = 0;
|
||||
else if (strcmp(s, "newfallback") == 0)
|
||||
call_trace = 1;
|
||||
else if (strcmp(s, "new") == 0)
|
||||
call_trace = 2;
|
||||
return 0;
|
||||
}
|
||||
early_param("call_trace", call_trace_setup);
|
||||
#endif
|
||||
|
@ -221,9 +221,7 @@ SECTIONS
|
||||
/* Sections to be discarded */
|
||||
/DISCARD/ : {
|
||||
*(.exitcall.exit)
|
||||
#ifndef CONFIG_UNWIND_INFO
|
||||
*(.eh_frame)
|
||||
#endif
|
||||
}
|
||||
|
||||
STABS_DEBUG
|
||||
|
@ -119,8 +119,6 @@
|
||||
*(__ksymtab_strings) \
|
||||
} \
|
||||
\
|
||||
EH_FRAME \
|
||||
\
|
||||
/* Built-in module parameters. */ \
|
||||
__param : AT(ADDR(__param) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start___param) = .; \
|
||||
@ -160,26 +158,6 @@
|
||||
*(.kprobes.text) \
|
||||
VMLINUX_SYMBOL(__kprobes_text_end) = .;
|
||||
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
#define EH_FRAME \
|
||||
/* Unwind data binary search table */ \
|
||||
. = ALIGN(8); \
|
||||
.eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start_unwind_hdr) = .; \
|
||||
*(.eh_frame_hdr) \
|
||||
VMLINUX_SYMBOL(__end_unwind_hdr) = .; \
|
||||
} \
|
||||
/* Unwind data */ \
|
||||
. = ALIGN(8); \
|
||||
.eh_frame : AT(ADDR(.eh_frame) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start_unwind) = .; \
|
||||
*(.eh_frame) \
|
||||
VMLINUX_SYMBOL(__end_unwind) = .; \
|
||||
}
|
||||
#else
|
||||
#define EH_FRAME
|
||||
#endif
|
||||
|
||||
/* DWARF debug sections.
|
||||
Symbols in the DWARF debugging sections are relative to
|
||||
the beginning of the section so we begin them at 0. */
|
||||
|
@ -1,95 +1,6 @@
|
||||
#ifndef _ASM_I386_UNWIND_H
|
||||
#define _ASM_I386_UNWIND_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002-2006 Novell, Inc.
|
||||
* Jan Beulich <jbeulich@novell.com>
|
||||
* This code is released under version 2 of the GNU GPL.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
struct unwind_frame_info
|
||||
{
|
||||
struct pt_regs regs;
|
||||
struct task_struct *task;
|
||||
unsigned call_frame:1;
|
||||
};
|
||||
|
||||
#define UNW_PC(frame) (frame)->regs.eip
|
||||
#define UNW_SP(frame) (frame)->regs.esp
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
#define UNW_FP(frame) (frame)->regs.ebp
|
||||
#define FRAME_RETADDR_OFFSET 4
|
||||
#define FRAME_LINK_OFFSET 0
|
||||
#define STACK_BOTTOM(tsk) STACK_LIMIT((tsk)->thread.esp0)
|
||||
#define STACK_TOP(tsk) ((tsk)->thread.esp0)
|
||||
#else
|
||||
#define UNW_FP(frame) ((void)(frame), 0)
|
||||
#endif
|
||||
#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1))
|
||||
|
||||
#define UNW_REGISTER_INFO \
|
||||
PTREGS_INFO(eax), \
|
||||
PTREGS_INFO(ecx), \
|
||||
PTREGS_INFO(edx), \
|
||||
PTREGS_INFO(ebx), \
|
||||
PTREGS_INFO(esp), \
|
||||
PTREGS_INFO(ebp), \
|
||||
PTREGS_INFO(esi), \
|
||||
PTREGS_INFO(edi), \
|
||||
PTREGS_INFO(eip)
|
||||
|
||||
#define UNW_DEFAULT_RA(raItem, dataAlign) \
|
||||
((raItem).where == Memory && \
|
||||
!((raItem).value * (dataAlign) + 4))
|
||||
|
||||
static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
|
||||
/*const*/ struct pt_regs *regs)
|
||||
{
|
||||
if (user_mode_vm(regs))
|
||||
info->regs = *regs;
|
||||
else {
|
||||
memcpy(&info->regs, regs, offsetof(struct pt_regs, esp));
|
||||
info->regs.esp = (unsigned long)®s->esp;
|
||||
info->regs.xss = __KERNEL_DS;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
|
||||
{
|
||||
memset(&info->regs, 0, sizeof(info->regs));
|
||||
info->regs.eip = info->task->thread.eip;
|
||||
info->regs.xcs = __KERNEL_CS;
|
||||
__get_user(info->regs.ebp, (long *)info->task->thread.esp);
|
||||
info->regs.esp = info->task->thread.esp;
|
||||
info->regs.xss = __KERNEL_DS;
|
||||
info->regs.xds = __USER_DS;
|
||||
info->regs.xes = __USER_DS;
|
||||
info->regs.xgs = __KERNEL_PDA;
|
||||
}
|
||||
|
||||
extern asmlinkage int arch_unwind_init_running(struct unwind_frame_info *,
|
||||
asmlinkage int (*callback)(struct unwind_frame_info *,
|
||||
void *arg),
|
||||
void *arg);
|
||||
|
||||
static inline int arch_unw_user_mode(/*const*/ struct unwind_frame_info *info)
|
||||
{
|
||||
return user_mode_vm(&info->regs)
|
||||
|| info->regs.eip < PAGE_OFFSET
|
||||
|| (info->regs.eip >= __fix_to_virt(FIX_VDSO)
|
||||
&& info->regs.eip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE)
|
||||
|| info->regs.esp < PAGE_OFFSET;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define UNW_PC(frame) ((void)(frame), 0)
|
||||
#define UNW_SP(frame) ((void)(frame), 0)
|
||||
#define UNW_FP(frame) ((void)(frame), 0)
|
||||
@ -99,6 +10,4 @@ static inline int arch_unw_user_mode(const void *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_I386_UNWIND_H */
|
||||
|
@ -1,100 +1,6 @@
|
||||
#ifndef _ASM_X86_64_UNWIND_H
|
||||
#define _ASM_X86_64_UNWIND_H
|
||||
|
||||
/*
|
||||
* Copyright (C) 2002-2006 Novell, Inc.
|
||||
* Jan Beulich <jbeulich@novell.com>
|
||||
* This code is released under version 2 of the GNU GPL.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/vsyscall.h>
|
||||
|
||||
struct unwind_frame_info
|
||||
{
|
||||
struct pt_regs regs;
|
||||
struct task_struct *task;
|
||||
unsigned call_frame:1;
|
||||
};
|
||||
|
||||
#define UNW_PC(frame) (frame)->regs.rip
|
||||
#define UNW_SP(frame) (frame)->regs.rsp
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
#define UNW_FP(frame) (frame)->regs.rbp
|
||||
#define FRAME_RETADDR_OFFSET 8
|
||||
#define FRAME_LINK_OFFSET 0
|
||||
#define STACK_BOTTOM(tsk) (((tsk)->thread.rsp0 - 1) & ~(THREAD_SIZE - 1))
|
||||
#define STACK_TOP(tsk) ((tsk)->thread.rsp0)
|
||||
#endif
|
||||
/* Might need to account for the special exception and interrupt handling
|
||||
stacks here, since normally
|
||||
EXCEPTION_STACK_ORDER < THREAD_ORDER < IRQSTACK_ORDER,
|
||||
but the construct is needed only for getting across the stack switch to
|
||||
the interrupt stack - thus considering the IRQ stack itself is unnecessary,
|
||||
and the overhead of comparing against all exception handling stacks seems
|
||||
not desirable. */
|
||||
#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1))
|
||||
|
||||
#define UNW_REGISTER_INFO \
|
||||
PTREGS_INFO(rax), \
|
||||
PTREGS_INFO(rdx), \
|
||||
PTREGS_INFO(rcx), \
|
||||
PTREGS_INFO(rbx), \
|
||||
PTREGS_INFO(rsi), \
|
||||
PTREGS_INFO(rdi), \
|
||||
PTREGS_INFO(rbp), \
|
||||
PTREGS_INFO(rsp), \
|
||||
PTREGS_INFO(r8), \
|
||||
PTREGS_INFO(r9), \
|
||||
PTREGS_INFO(r10), \
|
||||
PTREGS_INFO(r11), \
|
||||
PTREGS_INFO(r12), \
|
||||
PTREGS_INFO(r13), \
|
||||
PTREGS_INFO(r14), \
|
||||
PTREGS_INFO(r15), \
|
||||
PTREGS_INFO(rip)
|
||||
|
||||
#define UNW_DEFAULT_RA(raItem, dataAlign) \
|
||||
((raItem).where == Memory && \
|
||||
!((raItem).value * (dataAlign) + 8))
|
||||
|
||||
static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
|
||||
/*const*/ struct pt_regs *regs)
|
||||
{
|
||||
info->regs = *regs;
|
||||
}
|
||||
|
||||
static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
|
||||
{
|
||||
extern const char thread_return[];
|
||||
|
||||
memset(&info->regs, 0, sizeof(info->regs));
|
||||
info->regs.rip = (unsigned long)thread_return;
|
||||
info->regs.cs = __KERNEL_CS;
|
||||
__get_user(info->regs.rbp, (unsigned long *)info->task->thread.rsp);
|
||||
info->regs.rsp = info->task->thread.rsp;
|
||||
info->regs.ss = __KERNEL_DS;
|
||||
}
|
||||
|
||||
extern int arch_unwind_init_running(struct unwind_frame_info *,
|
||||
int (*callback)(struct unwind_frame_info *,
|
||||
void *arg),
|
||||
void *arg);
|
||||
|
||||
static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
|
||||
{
|
||||
return user_mode(&info->regs)
|
||||
|| (long)info->regs.rip >= 0
|
||||
|| (info->regs.rip >= VSYSCALL_START && info->regs.rip < VSYSCALL_END)
|
||||
|| (long)info->regs.rsp >= 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define UNW_PC(frame) ((void)(frame), 0UL)
|
||||
#define UNW_SP(frame) ((void)(frame), 0UL)
|
||||
|
||||
@ -103,6 +9,4 @@ static inline int arch_unw_user_mode(const void *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_64_UNWIND_H */
|
||||
|
@ -14,63 +14,6 @@
|
||||
|
||||
struct module;
|
||||
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
|
||||
#include <asm/unwind.h>
|
||||
|
||||
#ifndef ARCH_UNWIND_SECTION_NAME
|
||||
#define ARCH_UNWIND_SECTION_NAME ".eh_frame"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize unwind support.
|
||||
*/
|
||||
extern void unwind_init(void);
|
||||
extern void unwind_setup(void);
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
|
||||
extern void *unwind_add_table(struct module *,
|
||||
const void *table_start,
|
||||
unsigned long table_size);
|
||||
|
||||
extern void unwind_remove_table(void *handle, int init_only);
|
||||
|
||||
#endif
|
||||
|
||||
extern int unwind_init_frame_info(struct unwind_frame_info *,
|
||||
struct task_struct *,
|
||||
/*const*/ struct pt_regs *);
|
||||
|
||||
/*
|
||||
* Prepare to unwind a blocked task.
|
||||
*/
|
||||
extern int unwind_init_blocked(struct unwind_frame_info *,
|
||||
struct task_struct *);
|
||||
|
||||
/*
|
||||
* Prepare to unwind the currently running thread.
|
||||
*/
|
||||
extern int unwind_init_running(struct unwind_frame_info *,
|
||||
asmlinkage int (*callback)(struct unwind_frame_info *,
|
||||
void *arg),
|
||||
void *arg);
|
||||
|
||||
/*
|
||||
* Unwind to previous to frame. Returns 0 if successful, negative
|
||||
* number in case of an error.
|
||||
*/
|
||||
extern int unwind(struct unwind_frame_info *);
|
||||
|
||||
/*
|
||||
* Unwind until the return pointer is in user-land (or until an error
|
||||
* occurs). Returns 0 if successful, negative number in case of
|
||||
* error.
|
||||
*/
|
||||
extern int unwind_to_user(struct unwind_frame_info *);
|
||||
|
||||
#else
|
||||
|
||||
struct unwind_frame_info {};
|
||||
|
||||
static inline void unwind_init(void) {}
|
||||
@ -85,12 +28,12 @@ static inline void *unwind_add_table(struct module *mod,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline void unwind_remove_table(void *handle, int init_only)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline int unwind_init_frame_info(struct unwind_frame_info *info,
|
||||
struct task_struct *tsk,
|
||||
const struct pt_regs *regs)
|
||||
@ -122,6 +65,4 @@ static inline int unwind_to_user(struct unwind_frame_info *info)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_UNWIND_H */
|
||||
|
@ -31,7 +31,6 @@ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
|
||||
obj-$(CONFIG_UID16) += uid16.o
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_KALLSYMS) += kallsyms.o
|
||||
obj-$(CONFIG_STACK_UNWIND) += unwind.o
|
||||
obj-$(CONFIG_PM) += power/
|
||||
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
|
||||
obj-$(CONFIG_KEXEC) += kexec.o
|
||||
|
1305
kernel/unwind.c
1305
kernel/unwind.c
File diff suppressed because it is too large
Load Diff
@ -354,24 +354,6 @@ config FRAME_POINTER
|
||||
some architectures or if you use external debuggers.
|
||||
If you don't debug the kernel, you can say N.
|
||||
|
||||
config UNWIND_INFO
|
||||
bool "Compile the kernel with frame unwind information"
|
||||
depends on !IA64 && !PARISC && !ARM
|
||||
depends on !MODULES || !(MIPS || PPC || SUPERH || V850)
|
||||
help
|
||||
If you say Y here the resulting kernel image will be slightly larger
|
||||
but not slower, and it will give very useful debugging information.
|
||||
If you don't debug the kernel, you can say N, but we may not be able
|
||||
to solve problems without frame unwind information or frame pointers.
|
||||
|
||||
config STACK_UNWIND
|
||||
bool "Stack unwind support"
|
||||
depends on UNWIND_INFO
|
||||
depends on X86
|
||||
help
|
||||
This enables more precise stack traces, omitting all unrelated
|
||||
occurrences of pointers into kernel code from the dump.
|
||||
|
||||
config FORCED_INLINING
|
||||
bool "Force gcc to inline functions marked 'inline'"
|
||||
depends on DEBUG_KERNEL
|
||||
|
@ -55,37 +55,7 @@ static bool fail_task(struct fault_attr *attr, struct task_struct *task)
|
||||
|
||||
#define MAX_STACK_TRACE_DEPTH 32
|
||||
|
||||
#ifdef CONFIG_STACK_UNWIND
|
||||
|
||||
static asmlinkage int fail_stacktrace_callback(struct unwind_frame_info *info,
|
||||
void *arg)
|
||||
{
|
||||
int depth;
|
||||
struct fault_attr *attr = arg;
|
||||
bool found = (attr->require_start == 0 && attr->require_end == ULONG_MAX);
|
||||
|
||||
for (depth = 0; depth < attr->stacktrace_depth
|
||||
&& unwind(info) == 0 && UNW_PC(info); depth++) {
|
||||
if (arch_unw_user_mode(info))
|
||||
break;
|
||||
if (attr->reject_start <= UNW_PC(info) &&
|
||||
UNW_PC(info) < attr->reject_end)
|
||||
return false;
|
||||
if (attr->require_start <= UNW_PC(info) &&
|
||||
UNW_PC(info) < attr->require_end)
|
||||
found = true;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool fail_stacktrace(struct fault_attr *attr)
|
||||
{
|
||||
struct unwind_frame_info info;
|
||||
|
||||
return unwind_init_running(&info, fail_stacktrace_callback, attr);
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_STACKTRACE)
|
||||
#if defined(CONFIG_STACKTRACE)
|
||||
|
||||
static bool fail_stacktrace(struct fault_attr *attr)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user