diff options
| author | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
|---|---|---|
| committer | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
| commit | 5c34202b8bf942da411b6599668a76b07449bbfd (patch) | |
| tree | 5719c361321eaddc8e4f1b0c8a7994f0e9a6fdd3 /arch/arm/kernel/stacktrace.c | |
| parent | 0d4804b31f91cfbcff6d62af0bc09a893a1c8ae0 (diff) | |
| parent | 1f8a6b658a943b4f04a1fc7b3a420360202c86cd (diff) | |
Merge /pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'arch/arm/kernel/stacktrace.c')
| -rw-r--r-- | arch/arm/kernel/stacktrace.c | 73 | 
1 files changed, 73 insertions, 0 deletions
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c new file mode 100644 index 00000000000..77ef35efaa8 --- /dev/null +++ b/arch/arm/kernel/stacktrace.c @@ -0,0 +1,73 @@ +#include <linux/sched.h> +#include <linux/stacktrace.h> + +#include "stacktrace.h" + +int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, +		    int (*fn)(struct stackframe *, void *), void *data) +{ +	struct stackframe *frame; + +	do { +		/* +		 * Check current frame pointer is within bounds +		 */ +		if ((fp - 12) < low || fp + 4 >= high) +			break; + +		frame = (struct stackframe *)(fp - 12); + +		if (fn(frame, data)) +			break; + +		/* +		 * Update the low bound - the next frame must always +		 * be at a higher address than the current frame. +		 */ +		low = fp + 4; +		fp = frame->fp; +	} while (fp); + +	return 0; +} + +#ifdef CONFIG_STACKTRACE +struct stack_trace_data { +	struct stack_trace *trace; +	unsigned int skip; +}; + +static int save_trace(struct stackframe *frame, void *d) +{ +	struct stack_trace_data *data = d; +	struct stack_trace *trace = data->trace; + +	if (data->skip) { +		data->skip--; +		return 0; +	} + +	trace->entries[trace->nr_entries++] = frame->lr; + +	return trace->nr_entries >= trace->max_entries; +} + +void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +{ +	struct stack_trace_data data; +	unsigned long fp, base; + +	data.trace = trace; +	data.skip = trace->skip; + +	if (task) { +		base = (unsigned long)task_stack_page(task); +		fp = 0; /* FIXME */ +	} else { +		base = (unsigned long)task_stack_page(current); +		asm("mov %0, fp" : "=r" (fp)); +	} + +	walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data); +} +#endif  | 
