mirror of
https://github.com/torvalds/linux.git
synced 2024-12-16 16:12:52 +00:00
aa6f4d2b65
Add stacktrace support, which is required for lockdep and tracing. The stack tracing simply looks at all kernel text symbols found on the stack, similar to the trap stack dumping code, which can also be converted to use this. Signed-off-by: Rabin Vincent <rabin@rab.in> Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com>
77 lines
1.5 KiB
C
77 lines
1.5 KiB
C
#include <linux/sched.h>
|
|
#include <linux/stacktrace.h>
|
|
#include <linux/stacktrace.h>
|
|
#include <asm/stacktrace.h>
|
|
|
|
void walk_stackframe(unsigned long sp,
|
|
int (*fn)(unsigned long addr, void *data),
|
|
void *data)
|
|
{
|
|
unsigned long high = ALIGN(sp, THREAD_SIZE);
|
|
|
|
for (; sp <= high - 4; sp += 4) {
|
|
unsigned long addr = *(unsigned long *) sp;
|
|
|
|
if (!kernel_text_address(addr))
|
|
continue;
|
|
|
|
if (fn(addr, data))
|
|
break;
|
|
}
|
|
}
|
|
|
|
struct stack_trace_data {
|
|
struct stack_trace *trace;
|
|
unsigned int no_sched_functions;
|
|
unsigned int skip;
|
|
};
|
|
|
|
#ifdef CONFIG_STACKTRACE
|
|
|
|
static int save_trace(unsigned long addr, void *d)
|
|
{
|
|
struct stack_trace_data *data = d;
|
|
struct stack_trace *trace = data->trace;
|
|
|
|
if (data->no_sched_functions && in_sched_functions(addr))
|
|
return 0;
|
|
|
|
if (data->skip) {
|
|
data->skip--;
|
|
return 0;
|
|
}
|
|
|
|
trace->entries[trace->nr_entries++] = addr;
|
|
|
|
return trace->nr_entries >= trace->max_entries;
|
|
}
|
|
|
|
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
|
{
|
|
struct stack_trace_data data;
|
|
unsigned long sp;
|
|
|
|
data.trace = trace;
|
|
data.skip = trace->skip;
|
|
|
|
if (tsk != current) {
|
|
data.no_sched_functions = 1;
|
|
sp = tsk->thread.ksp;
|
|
} else {
|
|
data.no_sched_functions = 0;
|
|
sp = rdsp();
|
|
}
|
|
|
|
walk_stackframe(sp, save_trace, &data);
|
|
if (trace->nr_entries < trace->max_entries)
|
|
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
|
}
|
|
|
|
void save_stack_trace(struct stack_trace *trace)
|
|
{
|
|
save_stack_trace_tsk(current, trace);
|
|
}
|
|
EXPORT_SYMBOL_GPL(save_stack_trace);
|
|
|
|
#endif /* CONFIG_STACKTRACE */
|