[parisc-linux-cvs] linux-2.6 tausq
Randolph Chung
randolph at tausq.org
Fri Aug 13 10:34:05 MDT 2004
> Modified files:
> arch/parisc/kernel: unwind.c
> include/asm-parisc: assembly.h
>
> Log message:
> - fix unwind table search so it works reliably
> - add special case handling for ret_from_kernel_thread and _switch_to_ret
> - tidy up the code a bit
the special case handling of asm functions is quite ugly atm. i'll clean
it up some more.
Index: arch/parisc/kernel/unwind.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/unwind.c,v
retrieving revision 1.6
diff -u -p -r1.6 unwind.c
--- arch/parisc/kernel/unwind.c 9 Aug 2004 16:38:41 -0000 1.6
+++ arch/parisc/kernel/unwind.c 13 Aug 2004 16:32:43 -0000
@@ -12,8 +12,10 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/kallsyms.h>
#include <asm/uaccess.h>
+#include <asm/assembly.h>
#include <asm/unwind.h>
@@ -43,22 +45,24 @@ find_unwind_entry_in_table(const struct
const struct unwind_table_entry *e = 0;
unsigned long lo, hi, mid;
- for (lo = 0, hi = table->length; lo < hi; )
- {
- mid = (lo + hi) / 2;
+ lo = 0;
+ hi = table->length - 1;
+
+ while (lo <= hi) {
+ mid = (hi - lo) / 2 + lo;
e = &table->table[mid];
if (addr < e->region_start)
- hi = mid;
+ hi = mid - 1;
else if (addr > e->region_end)
lo = mid + 1;
else
- break;
+ return e;
}
- return e;
+ return NULL;
}
-static inline const struct unwind_table_entry *
+static const struct unwind_table_entry *
find_unwind_entry(unsigned long addr)
{
struct unwind_table *table = unwind_tables;
@@ -68,8 +72,7 @@ find_unwind_entry(unsigned long addr)
addr <= kernel_unwind_table.end)
e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
else
- for (; table; table = table->next)
- {
+ for (; table; table = table->next) {
if (addr >= table->start &&
addr <= table->end)
e = find_unwind_entry_in_table(table, addr);
@@ -99,6 +102,11 @@ unwind_table_init(struct unwind_table *t
table->next = NULL;
for (; start <= end; start++) {
+ if (start < end &&
+ start->region_end > (start+1)->region_start) {
+ printk("WARNING: Out of order unwind entry! %p and %p\n", start, start+1);
+ }
+
start->region_start += base_addr;
start->region_end += base_addr;
}
@@ -170,12 +178,40 @@ static void unwind_frame_regs(struct unw
int looking_for_rp, rpoffset = 0;
e = find_unwind_entry(info->ip);
- if (!e) {
+ if (e == NULL) {
unsigned long sp;
extern char _stext[], _etext[];
dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
+#ifdef CONFIG_KALLSYMS
+ /* Handle some frequent special cases.... */
+ {
+ char symname[KSYM_NAME_LEN+1];
+ char *modname;
+ unsigned long symsize, offset;
+
+ kallsyms_lookup(info->ip, &symsize, &offset,
+ &modname, symname);
+
+ dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
+
+ if (strcmp(symname, "_switch_to_ret") == 0) {
+ info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
+ info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
+ dbg("_switch_to_ret @ %lx - setting "
+ "prev_sp=%lx prev_ip=%lx\n",
+ info->ip, info->prev_sp,
+ info->prev_ip);
+ return;
+ } else if (strcmp(symname, "ret_from_kernel_thread") == 0 ||
+ strcmp(symname, "syscall_exit") == 0) {
+ info->prev_ip = info->prev_sp = 0;
+ return;
+ }
+ }
+#endif
+
/* Since we are doing the unwinding blind, we don't know if
we are adjusting the stack correctly or extracting the rp
correctly. The rp is checked to see if it belongs to the
@@ -199,16 +235,22 @@ static void unwind_frame_regs(struct unw
} 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 {
+ info->rp = 0;
- dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, Save_RP = %d size = %u\n",
- e->region_start, e->region_end, e->Save_SP, e->Save_RP, e->Total_frame_size);
+ 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", e->region_start,
+ e->region_end, e->Save_SP, e->Save_RP,
+ e->Total_frame_size);
looking_for_rp = e->Save_RP;
for (npc = e->region_start;
- (frame_size < (e->Total_frame_size << 3) || looking_for_rp) &&
+ (frame_size < (e->Total_frame_size << 3) ||
+ looking_for_rp) &&
npc < info->ip;
npc += 4) {
@@ -219,22 +261,28 @@ static void unwind_frame_regs(struct unw
/* 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) {
+ dbg("analyzing func @ %lx, insn=%08x @ "
+ "%lx, frame_size = %ld\n", info->ip,
+ insn, npc, frame_size);
+ } else if ((insn & 0xffe00008) == 0x73c00008) {
/* 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);
+ 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);
+ 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);
+ dbg("analyzing func @ %lx, insn=std rp,"
+ "-16(sp) @ %lx\n", info->ip, npc);
}
}
@@ -244,7 +292,9 @@ static void unwind_frame_regs(struct unw
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);
+ dbg("analyzing func @ %lx, setting prev_sp=%lx "
+ "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp,
+ info->prev_ip, npc);
}
}
@@ -257,7 +307,8 @@ void unwind_frame_init(struct unwind_fra
info->ip = ip;
info->rp = rp;
- dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", t ? (int)t->pid : 0, info->sp, info->ip);
+ dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n",
+ t ? (int)t->pid : -1, info->sp, info->ip);
}
void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
@@ -285,7 +336,9 @@ int unwind_once(struct unwind_frame_info
next_frame->prev_sp = 0;
next_frame->prev_ip = 0;
- dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", (int)next_frame->t->pid, next_frame->sp, next_frame->ip);
+ dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n",
+ next_frame->t ? (int)next_frame->t->pid : -1,
+ next_frame->sp, next_frame->ip);
return 0;
}
Index: include/asm-parisc/assembly.h
===================================================================
RCS file: /var/cvs/linux-2.6/include/asm-parisc/assembly.h,v
retrieving revision 1.4
diff -u -p -r1.4 assembly.h
--- include/asm-parisc/assembly.h 9 Aug 2004 02:23:45 -0000 1.4
+++ include/asm-parisc/assembly.h 13 Aug 2004 16:32:43 -0000
@@ -29,6 +29,7 @@
#define STREGM std,ma
#define RP_OFFSET 16
#define FRAME_SIZE 128
+#define CALLEE_SAVE_FRAME_SIZE 144
#else
#define LDREG ldw
#define STREG stw
@@ -37,6 +38,7 @@
#define STREGM stwm
#define RP_OFFSET 20
#define FRAME_SIZE 64
+#define CALLEE_SAVE_FRAME_SIZE 128
#endif
#ifdef CONFIG_PA20
@@ -292,7 +294,7 @@
#ifdef __LP64__
.macro callee_save
- std,ma %r3, 144(%r30)
+ std,ma %r3, CALLEE_SAVE_FRAME_SIZE(%r30)
mfctl %cr27, %r3
std %r4, -136(%r30)
std %r5, -128(%r30)
@@ -330,13 +332,13 @@
ldd -128(%r30), %r5
ldd -136(%r30), %r4
mtctl %r3, %cr27
- ldd,mb -144(%r30), %r3
+ ldd,mb -CALLEE_SAVE_FRAME_SIZE(%r30), %r3
.endm
#else /* ! __LP64__ */
.macro callee_save
- stw,ma %r3, 128(%r30)
+ stw,ma %r3, CALLEE_SAVE_FRAME_SIZE(%r30)
mfctl %cr27, %r3
stw %r4, -124(%r30)
stw %r5, -120(%r30)
@@ -374,7 +376,7 @@
ldw -120(%r30), %r5
ldw -124(%r30), %r4
mtctl %r3, %cr27
- ldw,mb -128(%r30), %r3
+ ldw,mb -CALLEE_SAVE_FRAME_SIZE(%r30), %r3
.endm
#endif /* ! __LP64__ */
More information about the parisc-linux-cvs
mailing list