unwind x86: Add dump_trace dwarf implementation

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h
index 70bbe39..ed31d6d 100644
--- a/arch/x86/include/asm/stacktrace.h
+++ b/arch/x86/include/asm/stacktrace.h
@@ -47,6 +47,12 @@
 		unsigned long *stack, unsigned long bp,
 		const struct stacktrace_ops *ops, void *data);
 
+#ifdef CONFIG_DWARF_UNWIND
+void dump_trace_dwarf(struct task_struct *task, struct pt_regs *regs,
+		      unsigned long *stack, unsigned long bp,
+		      const struct stacktrace_ops *ops, void *data);
+#endif
+
 #ifdef CONFIG_X86_32
 #define STACKSLOTS_PER_LINE 8
 #define get_bp(bp) asm("movl %%ebp, %0" : "=r" (bp) :)
diff --git a/arch/x86/kernel/dwarf_unwind/Makefile b/arch/x86/kernel/dwarf_unwind/Makefile
index 9a06b04..c8b91d5 100644
--- a/arch/x86/kernel/dwarf_unwind/Makefile
+++ b/arch/x86/kernel/dwarf_unwind/Makefile
@@ -1 +1 @@
-obj-y := regs.o
+obj-y := regs.o dumptrace.o
diff --git a/arch/x86/kernel/dwarf_unwind/dumptrace.c b/arch/x86/kernel/dwarf_unwind/dumptrace.c
new file mode 100644
index 0000000..950e3e0f
--- /dev/null
+++ b/arch/x86/kernel/dwarf_unwind/dumptrace.c
@@ -0,0 +1,50 @@
+
+#include <linux/dwarf_unwind.h>
+#include <asm/stacktrace.h>
+
+struct trace_data {
+	const struct stacktrace_ops *ops;
+	void *data;
+};
+
+static int unwind_trace(struct pt_regs *regs, void *data)
+{
+	struct trace_data *td = data;
+	const struct stacktrace_ops *ops = td->ops;
+
+	ops->address(td->data, regs->ip, 1);
+
+	return 0;
+}
+
+void dump_trace_dwarf(struct task_struct *task, struct pt_regs *regs,
+		      unsigned long *stack, unsigned long bp __maybe_unused,
+		      const struct stacktrace_ops *ops, void *data)
+{
+	struct trace_data td = {
+		.ops	= ops,
+		.data	= data,
+	};
+	struct pt_regs regs_tmp;
+	unsigned long dummy;
+
+	if (!task)
+		task = current;
+
+	if (!stack) {
+		if (regs)
+			stack = (unsigned long *) regs->sp;
+		else if (task != current)
+			stack = (unsigned long *) task->thread.sp;
+		else
+			stack = &dummy;
+	}
+
+	if (!regs) {
+		regs_load(&regs_tmp);
+		regs = &regs_tmp;
+		regs->sp = (unsigned long) stack;
+	}
+
+	dwarf_unwind(regs, unwind_trace, &td);
+}