11 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/slab.h>
18 #include <asm/uaccess.h>
20 #include <asm/asm-offsets.h>
21 #include <asm/ptrace.h>
23 #include <asm/unwind.h>
27 #define dbg(x...) printk(x)
32 #define KERNEL_START (KERNEL_BINARY_TEXT_START)
56 mid = (hi - lo) / 2 + lo;
70 find_unwind_entry(
unsigned long addr)
75 if (addr >= kernel_unwind_table.start &&
76 addr <= kernel_unwind_table.end)
77 e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
80 if (addr >= table->
start &&
82 e = find_unwind_entry_in_table(table, addr);
85 list_move(&table->
list, &unwind_tables);
95 unsigned long base_addr,
unsigned long gp,
96 void *table_start,
void *table_end)
108 table->
length = end - start + 1;
109 INIT_LIST_HEAD(&table->
list);
111 for (; start <=
end; start++) {
113 start->
region_end > (start+1)->region_start) {
114 printk(
"WARNING: Out of order unwind entry! %p and %p\n", start, start+1);
117 start->region_start += base_addr;
118 start->region_end += base_addr;
122 static int cmp_unwind_table_entry(
const void *
a,
const void *
b)
133 cmp_unwind_table_entry,
NULL);
139 void *start,
void *end)
146 unwind_table_sort(s, e);
151 unwind_table_init(table, name, base_addr, gp, start, end);
154 spin_unlock_irqrestore(&unwind_lock, flags);
165 spin_unlock_irqrestore(&unwind_lock, flags);
174 register unsigned long gp
__asm__ (
"r27");
181 printk(
"unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n",
185 unwind_table_init(&kernel_unwind_table,
"kernel",
KERNEL_START,
191 for (i = 0; i < 10; i++)
193 printk(
"region 0x%x-0x%x\n",
203 #define get_func_addr(fptr) fptr[2]
205 #define get_func_addr(fptr) fptr[0]
211 static unsigned long *hi = (
unsigned long *)&handle_interruption;
215 dbg(
"Unwinding through handle_interruption()\n");
231 int looking_for_rp, rpoffset = 0;
233 e = find_unwind_entry(info->
ip);
238 dbg(
"Cannot find unwind entry for 0x%lx; forced unwinding\n", info->
ip);
240 #ifdef CONFIG_KALLSYMS
249 dbg(
"info->ip = 0x%lx, name = %s\n", info->
ip, symname);
251 if (
strcmp(symname,
"_switch_to_ret") == 0) {
254 dbg(
"_switch_to_ret @ %lx - setting "
255 "prev_sp=%lx prev_ip=%lx\n",
259 }
else if (
strcmp(symname,
"ret_from_kernel_thread") == 0 ||
260 strcmp(symname,
"syscall_exit") == 0) {
284 }
while (info->
prev_ip < (
unsigned long)_stext ||
285 info->
prev_ip > (
unsigned long)_etext);
289 dbg(
"analyzing func @ %lx with no unwind info, setting "
290 "prev_sp=%lx prev_ip=%lx\n", info->
ip,
293 dbg(
"e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
294 "Save_RP = %d, Millicode = %d size = %u\n",
306 insn = *(
unsigned int *)npc;
308 if ((insn & 0xffffc000) == 0x37de0000 ||
309 (insn & 0xffe00000) == 0x6fc00000) {
311 frame_size += (insn & 0x1 ? -1 << 13 : 0) |
312 ((insn & 0x3fff) >> 1);
313 dbg(
"analyzing func @ %lx, insn=%08x @ "
314 "%lx, frame_size = %ld\n", info->
ip,
315 insn, npc, frame_size);
316 }
else if ((insn & 0xffe00008) == 0x73c00008) {
318 frame_size += (insn & 0x1 ? -1 << 13 : 0) |
319 (((insn >> 4) & 0x3ff) << 3);
320 dbg(
"analyzing func @ %lx, insn=%08x @ "
321 "%lx, frame_size = %ld\n", info->
ip,
322 insn, npc, frame_size);
323 }
else if (insn == 0x6bc23fd9) {
327 dbg(
"analyzing func @ %lx, insn=stw rp,"
328 "-20(sp) @ %lx\n", info->
ip, npc);
329 }
else if (insn == 0x0fc212c1) {
333 dbg(
"analyzing func @ %lx, insn=std rp,"
334 "-16(sp) @ %lx\n", info->
ip, npc);
338 if (!unwind_special(info, e->
region_start, frame_size)) {
341 info->
rp = info->
r31;
343 info->
rp = *(
unsigned long *)(info->
prev_sp - rpoffset);
348 dbg(
"analyzing func @ %lx, setting prev_sp=%lx "
349 "prev_ip=%lx npc=%lx\n", info->
ip, info->
prev_sp,
359 info->
sp = regs->
gr[30];
361 info->
rp = regs->
gr[2];
362 info->
r31 = regs->
gr[31];
364 dbg(
"(%d) Start unwind from sp=%08lx ip=%08lx\n",
365 t ? (
int)t->
pid : -1, info->
sp, info->
ip);
390 unwind_frame_regs(next_frame);
392 if (next_frame->
prev_sp == 0 ||
401 dbg(
"(%d) Continue unwind to sp=%08lx ip=%08lx\n",
402 next_frame->
t ? (
int)next_frame->
t->pid : -1,
403 next_frame->
sp, next_frame->
ip);
414 }
while (!ret && !(info->
ip & 3));
426 asm volatile (
"copy %%r30, %0" :
"=r"(
sp));
429 r.
gr[2] = (
unsigned long) __builtin_return_address(0);
441 }
while (info.
ip && level--);