12 #include <linux/kernel.h>
13 #include <linux/types.h>
14 #include <linux/errno.h>
16 #include <asm/ptrace.h>
17 #include <asm/processor.h>
20 #include <asm/stacktrace.h>
22 static u8 regcache[63];
46 static int lookup_prev_stack_frame(
unsigned long fp,
unsigned long pc,
47 unsigned long *pprev_fp,
unsigned long *pprev_pc,
53 unsigned long prologue = 0;
54 unsigned long fp_displacement = 0;
55 unsigned long fp_prev = 0;
56 unsigned long offset_r14 = 0, offset_r18 = 0;
57 int i, found_prologue_end = 0;
79 for (i = 0; i < 100; i++, prologue +=
sizeof(
unsigned long)) {
84 op = *(
unsigned long *)prologue;
86 major = (op >> 26) & 0x3f;
87 src = (op >> 20) & 0x3f;
88 minor = (op >> 16) & 0xf;
89 disp = (op >> 10) & 0x3f;
90 dest = (op >> 4) & 0x3f;
112 if (src == 15 && disp == 63 && dest == 14)
113 found_prologue_end = 1;
118 if (src != 15 || dest != 15)
121 fp_displacement -= regcache[disp];
122 fp_prev = fp - fp_displacement;
132 if (offset_r14 || fp_displacement == 0)
135 offset_r14 = (
u64)(((((
s64)op >> 10) & 0x3ff) << 54) >> 54);
136 offset_r14 *=
sizeof(
unsigned long);
137 offset_r14 += fp_displacement;
140 if (offset_r18 || fp_displacement == 0)
143 offset_r18 = (
u64)(((((
s64)op >> 10) & 0x3ff) << 54) >> 54);
144 offset_r18 *=
sizeof(
unsigned long);
145 offset_r18 += fp_displacement;
153 "specified in movi handler. Failed "
154 "opcode was 0x%lx: ", __func__,
162 ((((
s64)(
u64)op >> 10) & 0xffff) << 54) >> 54;
167 if (src != 15 || dest != 15)
172 (
u64)(((((
s64)op >> 10) & 0x3ff) << 54) >> 54);
173 fp_prev = fp - fp_displacement;
177 if (found_prologue_end && offset_r14 && (offset_r18 || *pprev_pc) && fp_prev)
181 if (offset_r14 == 0 || fp_prev == 0) {
183 pr_debug(
"Unable to find r14 offset\n");
185 pr_debug(
"Unable to find previous fp\n");
191 if (!*pprev_pc && (offset_r18 == 0))
194 *pprev_fp = *(
unsigned long *)(fp_prev + offset_r14);
197 *pprev_pc = *(
unsigned long *)(fp_prev + offset_r18);
209 static struct pt_regs here_regs;
220 unsigned long pc,
unsigned long fp)
224 sh64_unwind_inner(ops, data, (
struct pt_regs *)fp);
228 void *data,
struct pt_regs *regs)
230 unsigned long pc,
fp;
240 unsigned long next_fp, next_pc;
242 if (pc == ((
unsigned long)&syscall_ret & ~1)) {
244 unwind_nested(ops, data, pc, fp);
248 if (pc == ((
unsigned long)&ret_from_syscall & ~1)) {
249 printk(
"SYSCALL (PREEMPTED)\n");
250 unwind_nested(ops, data, pc, fp);
256 if (pc == ((
unsigned long)&ret_from_exception & ~1)) {
258 unwind_nested(ops, data, pc, fp);
262 if (pc == ((
unsigned long)&ret_from_irq & ~1)) {
264 unwind_nested(ops, data, pc, fp);
269 ((pc & 3) == 0) && ((fp & 7) == 0));
279 next_pc = regs->
regs[18];
284 if (lookup_prev_stack_frame(fp, pc, &next_fp, &next_pc, regs) == 0) {
285 ofs =
sizeof(
unsigned long);
289 printk(
"Unable to lookup previous stack frame\n");
311 __asm__ __volatile__ (
"ori r14, 0, %0" :
"=r" (regs->
regs[14]));
312 __asm__ __volatile__ (
"ori r15, 0, %0" :
"=r" (regs->
regs[15]));
313 __asm__ __volatile__ (
"ori r18, 0, %0" :
"=r" (regs->
regs[18]));
315 __asm__ __volatile__ (
"gettr tr0, %0" :
"=r" (regs->
tregs[0]));
316 __asm__ __volatile__ (
"gettr tr1, %0" :
"=r" (regs->
tregs[1]));
317 __asm__ __volatile__ (
"gettr tr2, %0" :
"=r" (regs->
tregs[2]));
318 __asm__ __volatile__ (
"gettr tr3, %0" :
"=r" (regs->
tregs[3]));
319 __asm__ __volatile__ (
"gettr tr4, %0" :
"=r" (regs->
tregs[4]));
320 __asm__ __volatile__ (
"gettr tr5, %0" :
"=r" (regs->
tregs[5]));
321 __asm__ __volatile__ (
"gettr tr6, %0" :
"=r" (regs->
tregs[6]));
322 __asm__ __volatile__ (
"gettr tr7, %0" :
"=r" (regs->
tregs[7]));
332 sh64_unwind_inner(ops, data, regs);
335 static struct unwinder sh64_unwinder = {
336 .name =
"sh64-unwinder",
337 .dump = sh64_unwinder_dump,
341 static int __init sh64_unwinder_init(
void)