X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fparisc%2Fkernel%2Funwind.c;fp=arch%2Fparisc%2Fkernel%2Funwind.c;h=abd749074a5ae9d20e796ae8baf1fb4fd0ce767b;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=ccfd5fe5afb9ab34ded18731ac2a9d86239e0da7;hpb=db216c3d5e4c040e557a50f8f5d35d5c415e8c1c;p=linux-2.6.git diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c index ccfd5fe5a..abd749074 100644 --- a/arch/parisc/kernel/unwind.c +++ b/arch/parisc/kernel/unwind.c @@ -8,18 +8,6 @@ * understand what is happening here */ -/* - * J. David Anglin writes: - * - * "You have to adjust the current sp to that at the begining of the function. - * There can be up to two stack additions to allocate the frame in the - * prologue. Similar things happen in the epilogue. In the presence of - * interrupts, you have to be concerned about where you are in the function - * and what stack adjustments have taken place." - * - * For now these cases are not handled, but they should be! - */ - #include #include #include @@ -36,8 +24,8 @@ #define dbg(x...) #endif -extern const struct unwind_table_entry __start___unwind[]; -extern const struct unwind_table_entry __stop___unwind[]; +extern struct unwind_table_entry __start___unwind[]; +extern struct unwind_table_entry __stop___unwind[]; static spinlock_t unwind_lock; /* @@ -55,8 +43,6 @@ find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr) const struct unwind_table_entry *e = 0; unsigned long lo, hi, mid; - addr -= table->base_addr; - for (lo = 0, hi = table->length; lo < hi; ) { mid = (lo + hi) / 2; @@ -97,10 +83,11 @@ find_unwind_entry(unsigned long addr) static void unwind_table_init(struct unwind_table *table, const char *name, unsigned long base_addr, unsigned long gp, - const void *table_start, const void *table_end) + void *table_start, void *table_end) { - const struct unwind_table_entry *start = table_start; - const struct unwind_table_entry *end = table_end - 1; + struct unwind_table_entry *start = table_start; + struct unwind_table_entry *end = + (struct unwind_table_entry *)table_end - 1; table->name = name; table->base_addr = base_addr; @@ -108,14 +95,19 @@ unwind_table_init(struct unwind_table *table, const char *name, table->start = base_addr + start->region_start; table->end = base_addr + end->region_end; table->table = (struct unwind_table_entry *)table_start; - table->length = end - start; + table->length = end - start + 1; table->next = NULL; + + for (; start <= end; start++) { + start->region_start += base_addr; + start->region_end += base_addr; + } } void * unwind_table_add(const char *name, unsigned long base_addr, unsigned long gp, - const void *start, const void *end) + void *start, void *end) { struct unwind_table *table; unsigned long flags; @@ -206,6 +198,8 @@ static void unwind_frame_regs(struct unwind_frame_info *info) sp = info->prev_sp; } while (info->prev_ip < (unsigned long)_stext || info->prev_ip > (unsigned long)_etext); + + dbg("analyzing func @ %lx with no unwind info, setting prev_sp=%lx prev_ip=%lx\n", info->ip, info->prev_sp, info->prev_ip); } else { dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, Save_RP = %d size = %u\n", @@ -225,42 +219,57 @@ static void unwind_frame_regs(struct unwind_frame_info *info) /* ldo X(sp), sp, or stwm X,D(sp) */ frame_size += (insn & 0x1 ? -1 << 13 : 0) | ((insn & 0x3fff) >> 1); + dbg("analyzing func @ %lx, insn=%08x @ %lx, frame_size = %ld\n", info->ip, insn, npc, frame_size); } else if ((insn & 0xffe00008) == 0x7ec00008) { /* std,ma X,D(sp) */ frame_size += (insn & 0x1 ? -1 << 13 : 0) | (((insn >> 4) & 0x3ff) << 3); + dbg("analyzing func @ %lx, insn=%08x @ %lx, frame_size = %ld\n", info->ip, insn, npc, frame_size); } else if (insn == 0x6bc23fd9) { /* stw rp,-20(sp) */ rpoffset = 20; looking_for_rp = 0; + dbg("analyzing func @ %lx, insn=stw rp,-20(sp) @ %lx\n", info->ip, npc); } else if (insn == 0x0fc212c1) { /* std rp,-16(sr0,sp) */ rpoffset = 16; looking_for_rp = 0; + dbg("analyzing func @ %lx, insn=std rp,-16(sp) @ %lx\n", info->ip, npc); } } info->prev_sp = info->sp - frame_size; if (rpoffset) - info->prev_ip = *(unsigned long *)(info->prev_sp - rpoffset); + info->rp = *(unsigned long *)(info->prev_sp - rpoffset); + info->prev_ip = info->rp; + info->rp = 0; + + dbg("analyzing func @ %lx, setting prev_sp=%lx prev_ip=%lx\n", info->ip, info->prev_sp, info->prev_ip); } } void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, - struct pt_regs *regs) + unsigned long sp, unsigned long ip, unsigned long rp) { memset(info, 0, sizeof(struct unwind_frame_info)); info->t = t; - info->sp = regs->ksp; - info->ip = regs->kpc; + info->sp = sp; + info->ip = ip; + info->rp = rp; - dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", (int)t->pid, info->sp, info->ip); + dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", t ? (int)t->pid : 0, info->sp, info->ip); } void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t) { struct pt_regs *regs = &t->thread.regs; - unwind_frame_init(info, t, regs); + unwind_frame_init(info, t, regs->ksp, regs->kpc, 0); +} + +void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs) +{ + unwind_frame_init(info, current, regs->gr[30], regs->iaoq[0], + regs->gr[2]); } int unwind_once(struct unwind_frame_info *next_frame)