blob: 2e2cc83840070473ca45307c5bfb4bb12d2ee63d [file] [log] [blame]
#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 */