unwind x86: Add dump_trace switch for legacy and dwarf backtrace
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/kernel/dumptrace.c b/arch/x86/kernel/dumptrace.c
index 3cb943f..2e2cc83 100644
--- a/arch/x86/kernel/dumptrace.c
+++ b/arch/x86/kernel/dumptrace.c
@@ -1,7 +1,75 @@
#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/kobject.h>
#include <asm/stacktrace.h>
+#include <asm/ptrace.h>
dump_trace_t dump_trace = dump_trace_legacy;
EXPORT_SYMBOL(dump_trace);
+
+#ifdef CONFIG_DWARF_UNWIND
+struct backtrace {
+ const char *name;
+ dump_trace_t fn;
+};
+
+enum {
+ BACKTRACE_LEGACY = 0,
+ BACKTRACE_DWARF = 1,
+};
+
+static struct backtrace bt[] = {
+ [BACKTRACE_LEGACY] = {
+ .name = "legacy",
+ .fn = dump_trace_legacy,
+ },
+ [BACKTRACE_DWARF] = {
+ .name = "dwarf",
+ .fn = dump_trace_dwarf,
+ },
+};
+
+static int bt_idx;
+static DEFINE_SPINLOCK(bt_lock);
+
+int backtrace_switch(int i)
+{
+ struct backtrace *b = &bt[i];
+ unsigned long flags;
+
+ spin_lock_irqsave(&bt_lock, flags);
+ dump_trace = b->fn;
+ bt_idx = i;
+ spin_unlock_irqrestore(&bt_lock, flags);
+ return 0;
+}
+
+ssize_t backtrace_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ struct backtrace *b = &bt[bt_idx];
+ return sprintf(buf, "%s\n", b->name);
+}
+
+ssize_t backtrace_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int i, ret = -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(bt); i++) {
+ struct backtrace *b = &bt[i];
+
+ if (!strncmp(buf, b->name, strlen(b->name))) {
+ ret = backtrace_switch(i);
+ break;
+ }
+ }
+
+ return ret < 0 ? ret : count;
+}
+#endif /* CONFIG_DWARF_UNWIND */
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index 9659d38..ec92a6d 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -132,6 +132,25 @@
#endif /* CONFIG_KEXEC */
+#ifdef CONFIG_DWARF_UNWIND
+__weak ssize_t backtrace_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ WARN(1, "backtrace switch not implemented\n");
+ return -ENODEV;
+}
+
+__weak ssize_t backtrace_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ WARN(1, "backtrace switch not implemented\n");
+ return -ENODEV;
+}
+KERNEL_ATTR_RW(backtrace);
+#endif
+
/* whether file capabilities are enabled */
static ssize_t fscaps_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
@@ -197,6 +216,9 @@
&vmcoreinfo_attr.attr,
#endif
&rcu_expedited_attr.attr,
+#ifdef CONFIG_DWARF_UNWIND
+ &backtrace_attr.attr,
+#endif
NULL
};