--- /dev/null
+Subject: DWARF2 EH-frame based stack unwinding
+From: jbeulich@novell.com
+Patch-mainline: no
+
+Automatically created from "patches.suse/stack-unwind" by xen-port-patches.py
+
+--- sle11-2009-05-14.orig/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:20:49.000000000 +0200
++++ sle11-2009-05-14/arch/x86/kernel/entry_32-xen.S 2009-05-14 11:29:34.000000000 +0200
+@@ -1290,6 +1290,38 @@ ENTRY(fixup_4gb_segment)
+ CFI_ENDPROC
+ END(spurious_interrupt_bug)
+
++#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 $__KERNEL_PERCPU, PT_FS(%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
+--- sle11-2009-05-14.orig/arch/x86/kernel/entry_64-xen.S 2009-03-16 16:38:16.000000000 +0100
++++ sle11-2009-05-14/arch/x86/kernel/entry_64-xen.S 2008-11-25 13:17:09.000000000 +0100
+@@ -1419,3 +1419,36 @@ KPROBE_ENTRY(ignore_sysret)
+ HYPERVISOR_IRET 0
+ CFI_ENDPROC
+ ENDPROC(ignore_sysret)
++
++#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
+--- sle11-2009-05-14.orig/arch/x86/kernel/traps_32-xen.c 2008-11-25 13:17:06.000000000 +0100
++++ sle11-2009-05-14/arch/x86/kernel/traps_32-xen.c 2008-11-25 13:17:09.000000000 +0100
+@@ -86,6 +86,11 @@ int panic_on_unrecovered_nmi;
+ int panic_on_io_nmi;
+ int kstack_depth_to_print = 24;
+ static unsigned int code_bytes = 64;
++#ifdef CONFIG_STACK_UNWIND
++static int call_trace = 1;
++#else
++#define call_trace (-1)
++#endif
+ static int ignore_nmis;
+ static int die_counter;
+
+@@ -156,6 +161,33 @@ print_context_stack(struct thread_info *
+ return bp;
+ }
+
++struct ops_and_data {
++ const 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), 1);
++ 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;
++}
++
+ void dump_trace(struct task_struct *task, struct pt_regs *regs,
+ unsigned long *stack, unsigned long bp,
+ const struct stacktrace_ops *ops, void *data)
+@@ -163,6 +195,40 @@ void dump_trace(struct task_struct *task
+ 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\n",
++ UNW_PC(&info));
++ if (UNW_SP(&info) >= PAGE_OFFSET) {
++ ops->warning(data, "Leftover inexact backtrace:\n");
++ stack = (void *)UNW_SP(&info);
++ if (!stack)
++ return;
++ bp = UNW_FP(&info);
++ } else
++ ops->warning(data, "Full inexact backtrace again:\n");
++ } else if (call_trace >= 1)
++ return;
++ else
++ ops->warning(data, "Full inexact backtrace again:\n");
++ } else
++ ops->warning(data, "Inexact backtrace:\n");
++ }
++
+ if (!stack) {
+ unsigned long dummy;
+ stack = &dummy;
+@@ -1226,3 +1292,19 @@ static int __init code_bytes_setup(char
+ return 1;
+ }
+ __setup("code_bytes=", code_bytes_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
+--- sle11-2009-05-14.orig/arch/x86/kernel/traps_64-xen.c 2008-11-25 13:17:06.000000000 +0100
++++ sle11-2009-05-14/arch/x86/kernel/traps_64-xen.c 2008-11-25 13:17:09.000000000 +0100
+@@ -59,6 +59,11 @@ int panic_on_unrecovered_nmi;
+ int panic_on_io_nmi;
+ int kstack_depth_to_print = 12;
+ static unsigned int code_bytes = 64;
++#ifdef CONFIG_STACK_UNWIND
++static int call_trace = 1;
++#else
++#define call_trace (-1)
++#endif
+ static int ignore_nmis;
+ static int die_counter;
+
+@@ -165,6 +170,32 @@ static unsigned long *in_exception_stack
+ return NULL;
+ }
+
++struct ops_and_data {
++ const 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), 1);
++ 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;
++}
++
+ /*
+ * x86-64 can have up to three kernel stacks:
+ * process stack
+@@ -229,6 +260,42 @@ void dump_trace(struct task_struct *task
+ 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\n",
++ UNW_PC(&info));
++ if ((long)UNW_SP(&info) < 0) {
++ ops->warning(data, "Leftover inexact backtrace:\n");
++ stack = (unsigned long *)UNW_SP(&info);
++ if (!stack) {
++ put_cpu();
++ return;
++ }
++ } else
++ ops->warning(data, "Full inexact backtrace again:\n");
++ } else if (call_trace >= 1) {
++ put_cpu();
++ return;
++ } else
++ ops->warning(data, "Full inexact backtrace again:\n");
++ } else
++ ops->warning(data, "Inexact backtrace:\n");
++ }
++
+ if (!stack) {
+ unsigned long dummy;
+ stack = &dummy;
+@@ -1242,3 +1309,21 @@ static int __init code_bytes_setup(char
+ return 1;
+ }
+ __setup("code_bytes=", code_bytes_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