[PARISC] unwinder improvements
authorRandolph Chung <tausq@debian.org>
Tue, 12 Jun 2007 06:27:32 +0000 (14:27 +0800)
committerKyle McMartin <kyle@minerva.i.cabal.ca>
Thu, 21 Jun 2007 21:46:22 +0000 (17:46 -0400)
Add special-case handling for "handle_interruption" so that we can rewind
past the interruption. This is useful for seeing what caused a BUG() or
WARN_ON(); otherwise the unwind stops at the interruption.

Signed-off-by: Randolph Chung <tausq@debian.org>
Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
arch/parisc/kernel/unwind.c

index cad9d78312e00f6bd121146feceeb238a4fd9e86..322167737de75a7cfa261f12dcd8f31ad724cca4 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <asm/uaccess.h>
 #include <asm/assembly.h>
+#include <asm/asm-offsets.h>
+#include <asm/ptrace.h>
 
 #include <asm/unwind.h>
 
@@ -199,6 +201,29 @@ static int unwind_init(void)
        return 0;
 }
 
+#ifdef CONFIG_64BIT
+#define get_func_addr(fptr) fptr[2]
+#else
+#define get_func_addr(fptr) fptr[0]
+#endif
+
+static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int frame_size)
+{
+       void handle_interruption(int, struct pt_regs *);
+       static unsigned long *hi = (unsigned long)&handle_interruption;
+
+       if (pc == get_func_addr(hi)) {
+               struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
+               dbg("Unwinding through handle_interruption()\n");
+               info->prev_sp = regs->gr[30];
+               info->prev_ip = regs->iaoq[0];
+
+               return 1;
+       }
+
+       return 0;
+}
+
 static void unwind_frame_regs(struct unwind_frame_info *info)
 {
        const struct unwind_table_entry *e;
@@ -312,13 +337,15 @@ static void unwind_frame_regs(struct unwind_frame_info *info)
                        }
                }
 
-               info->prev_sp = info->sp - frame_size;
-               if (e->Millicode)
-                       info->rp = info->r31;
-               else if (rpoffset)
-                       info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
-               info->prev_ip = info->rp;
-               info->rp = 0;
+               if (!unwind_special(info, e->region_start, frame_size)) {
+                       info->prev_sp = info->sp - frame_size;
+                       if (e->Millicode)
+                               info->rp = info->r31;
+                       else if (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 npc=%lx\n", info->ip, info->prev_sp,