17 #include <linux/kernel.h>
18 #include <linux/sched.h>
20 #include <linux/types.h>
21 #include <linux/errno.h>
22 #include <linux/module.h>
24 #include <asm/sections.h>
25 #include <asm/exceptions.h>
26 #include <asm/unwind.h>
27 #include <asm/switch_to.h>
64 return abs((
s16)(instr & 0xFFFF));
76 static unsigned long *find_frame_creation(
unsigned long *
pc)
85 for (i = 0; i < 1000; i++, pc--) {
95 if ((instr & 0xFFFF0000) != 0x30210000)
99 if ((frame_size < 8) || (frame_size & 3)) {
100 pr_debug(
" Invalid frame size %d at 0x%p\n",
105 pr_debug(
" Found frame creation at 0x%p, size %d\n", pc,
124 static int lookup_prev_stack_frame(
unsigned long fp,
unsigned long pc,
125 unsigned long leaf_return,
126 unsigned long *pprev_fp,
127 unsigned long *pprev_pc)
129 unsigned long *prologue =
NULL;
133 prologue = find_frame_creation((
unsigned long *)pc);
138 *pprev_fp = fp + frame_size;
139 *pprev_pc = *(
unsigned long *)fp;
143 *pprev_pc = leaf_return;
150 return (!*pprev_pc || (*pprev_pc & 3)) ? -
EINVAL : 0;
154 unsigned long pc,
unsigned long fp,
155 unsigned long leaf_return,
156 struct stack_trace *
trace);
163 static inline void unwind_trap(
struct task_struct *
task,
unsigned long pc,
164 unsigned long fp,
struct stack_trace *
trace)
169 static inline void unwind_trap(
struct task_struct *
task,
unsigned long pc,
170 unsigned long fp,
struct stack_trace *
trace)
173 microblaze_unwind_inner(task, regs->
pc, regs->
r1, regs->
r15, trace);
188 unsigned long pc,
unsigned long fp,
189 unsigned long leaf_return,
190 struct stack_trace *
trace)
194 pr_debug(
" Unwinding with PC=%p, FP=%p\n", (
void *)pc, (
void *)fp);
195 if (!pc || !fp || (pc & 3) || (fp & 3)) {
196 pr_debug(
" Invalid state for unwind, aborting\n");
200 unsigned long next_fp, next_pc = 0;
201 unsigned long return_to = pc + 2 *
sizeof(
unsigned long);
206 if ((return_to >= (
unsigned long)&_hw_exception_handler)
207 &&(return_to < (
unsigned long)&ex_handler_unhandled)) {
218 microblaze_unwind_inner(task, regs->
r17 - 4,
219 fp + EX_HANDLER_STACK_SIZ,
228 && (return_to <= handler->end_addr)) {
231 unwind_trap(task, pc, fp, trace);
238 #ifdef CONFIG_STACKTRACE
242 trace->entries[trace->nr_entries++] =
pc;
244 if (trace->nr_entries >= trace->max_entries)
250 pr_info(
"[<%p>] PID %lu [%s]\n",
252 (
unsigned long) task->
pid,
263 if (lookup_prev_stack_frame(fp, pc, leaf_return, &next_fp,
265 ofs =
sizeof(
unsigned long);
270 pr_debug(
" Failed to find previous stack frame\n");
274 pr_debug(
" Next PC=%p, next FP=%p\n",
275 (
void *)next_pc, (
void *)next_fp);
290 microblaze_unwind_inner(task, regs->
pc, regs->
r1,
294 (
struct thread_info *)(task->
stack);
296 &thread_info->cpu_context;
298 microblaze_unwind_inner(task,
299 (
unsigned long) &_switch_to,
301 cpu_context->r15, trace);
304 unsigned long pc,
fp;
306 __asm__ __volatile__ (
"or %0, r1, r0" :
"=r" (fp));
316 microblaze_unwind_inner(
current, pc, fp, 0, trace);