Kernel debugging helpers
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 19 May 2011 01:27:21 +0000 (18:27 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:03 +0000 (17:36 -0700)
Moved backtrace to arch/kdebug.c, added helpers to get your function's
caller's PC (roughly), and to get the name of a function that holds a
given PC.  Sparc compiles, though doesn't support the two new helpers.

13 files changed:
kern/arch/i686/arch.h
kern/arch/i686/cpuinfo.c
kern/arch/i686/kdebug.c
kern/arch/i686/kdebug.h [new file with mode: 0644]
kern/arch/sparc/Makefrag
kern/arch/sparc/arch.h
kern/arch/sparc/cpuinfo.c
kern/arch/sparc/kdebug.c [new file with mode: 0644]
kern/arch/sparc/kdebug.h [new file with mode: 0644]
kern/arch/sparc/trap.c
kern/include/kdebug.h
kern/src/Makefrag
kern/src/kdebug.c [new file with mode: 0644]

index 52c0541..2266e54 100644 (file)
@@ -33,7 +33,6 @@ static __inline void reboot(void) __attribute__((always_inline)) __attribute__((
 
 void print_cpuinfo(void);
 void show_mapping(uintptr_t start, size_t size);
-void backtrace(void);
 
 /* declared in smp.c */
 int hw_coreid_lookup[MAX_NUM_CPUS];
index ff05d48..237c42d 100644 (file)
@@ -150,43 +150,6 @@ void show_mapping(uintptr_t start, size_t size)
        }
 }
 
-void backtrace(void)
-{ TRUSTEDBLOCK
-       extern char (SNT RO _start)[];
-       uint32_t *ebp, eip;
-       eipdebuginfo_t debuginfo;
-       char buf[256];
-       int j, i = 1;
-       ebp = (uint32_t*)read_ebp();
-       // this is part of the way back into the call() instruction's bytes
-       // eagle-eyed readers should be able to explain why this is good enough,
-       // and retaddr (just *(ebp + 1) is not)
-       eip = *(ebp + 1) - 1;
-       // jump back a frame (out of backtrace)
-       ebp = (uint32_t*)(*ebp);
-       printk("Stack Backtrace on Core %d:\n", core_id());
-       // on each iteration, ebp holds the stack frame and eip an addr in that func
-       while (ebp != 0) {
-               debuginfo_eip(eip, &debuginfo);
-               memset(buf, 0, 256);
-               strncpy(buf, debuginfo.eip_fn_name, MIN(debuginfo.eip_fn_namelen, 256));
-               buf[MIN(debuginfo.eip_fn_namelen, 255)] = 0;
-               cprintf("#%02d [<%p>] in %s+%x(%p) from %s:%d\n", i++,  eip, buf, 
-                       debuginfo.eip_fn_addr - (uint32_t)_start, debuginfo.eip_fn_addr, 
-                       debuginfo.eip_file, debuginfo.eip_line);
-               cprintf("    ebp: %x   Args:", ebp);
-               for (j = 0; j < MIN(debuginfo.eip_fn_narg, 5); j++)
-                       cprintf(" %08x", *(ebp + 2 + j));
-               cprintf("\n");
-               eip = *(ebp + 1) - 1;
-               ebp = (uint32_t*)(*ebp);
-               #ifdef __CONFIG_RESET_STACKS__
-               if (!strncmp("__smp_idle", debuginfo.eip_fn_name, 10))
-                       break;
-               #endif /* __CONFIG_RESET_STACKS__ */
-       }
-}
-
 /* Like backtrace, this is probably not the best place for this. */
 void spinlock_debug(spinlock_t *lock)
 {
index 3ebf3c4..48af7b4 100644 (file)
@@ -295,3 +295,40 @@ void *debug_get_fn_addr(char *fn_name)
        }
        return retval;
 }
+
+void backtrace(void)
+{ 
+       extern char (SNT RO _start)[];
+       uint32_t *ebp, eip;
+       eipdebuginfo_t debuginfo;
+       char buf[256];
+       int j, i = 1;
+       ebp = (uint32_t*)read_ebp();
+       // this is part of the way back into the call() instruction's bytes
+       // eagle-eyed readers should be able to explain why this is good enough,
+       // and retaddr (just *(ebp + 1) is not)
+       eip = *(ebp + 1) - 1;
+       // jump back a frame (out of backtrace)
+       ebp = (uint32_t*)(*ebp);
+       printk("Stack Backtrace on Core %d:\n", core_id());
+       // on each iteration, ebp holds the stack frame and eip an addr in that func
+       while (ebp != 0) {
+               debuginfo_eip(eip, &debuginfo);
+               memset(buf, 0, 256);
+               strncpy(buf, debuginfo.eip_fn_name, MIN(debuginfo.eip_fn_namelen, 256));
+               buf[MIN(debuginfo.eip_fn_namelen, 255)] = 0;
+               cprintf("#%02d [<%p>] in %s+%x(%p) from %s:%d\n", i++,  eip, buf, 
+                       debuginfo.eip_fn_addr - (uint32_t)_start, debuginfo.eip_fn_addr, 
+                       debuginfo.eip_file, debuginfo.eip_line);
+               cprintf("    ebp: %x   Args:", ebp);
+               for (j = 0; j < MIN(debuginfo.eip_fn_narg, 5); j++)
+                       cprintf(" %08x", *(ebp + 2 + j));
+               cprintf("\n");
+               eip = *(ebp + 1) - 1;
+               ebp = (uint32_t*)(*ebp);
+               #ifdef __CONFIG_RESET_STACKS__
+               if (!strncmp("__smp_idle", debuginfo.eip_fn_name, 10))
+                       break;
+               #endif /* __CONFIG_RESET_STACKS__ */
+       }
+}
diff --git a/kern/arch/i686/kdebug.h b/kern/arch/i686/kdebug.h
new file mode 100644 (file)
index 0000000..291d8c4
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (c) 2011 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * x86-specific Kernel debugging headers and static inlines */
+
+#ifndef ROS_KERN_ARCH_KDEBUG_H
+#define ROS_KERN_ARCH_KDEBUG_H
+
+#include <ros/common.h>
+#include <arch/x86.h>
+
+#include <stdio.h>
+
+/* Returns a PC/EIP in the function that called us, preferably near the call
+ * site.  Returns 0 when we can't jump back any farther. */
+static inline uintptr_t get_caller_pc(void)
+{
+       uint32_t *ebp = (uint32_t*)read_ebp();
+       if (!ebp)
+               return 0;
+       /* this is part of the way back into the call() instruction's bytes
+        * eagle-eyed readers should be able to explain why this is good enough, and
+        * retaddr (just *(ebp + 1) is not) */
+       return *(ebp + 1) - 1;
+}
+
+#endif /* ROS_KERN_ARCH_KDEBUG_H */
index c9e37e9..a7f849f 100644 (file)
@@ -30,5 +30,6 @@ KERN_ARCH_SRCFILES := $(KERN_ARCH_SRC_DIR)/entry.S \
                       $(KERN_ARCH_SRC_DIR)/fpu.c \
                       $(KERN_ARCH_SRC_DIR)/sparcfpu.c \
                       $(KERN_ARCH_SRC_DIR)/softfloat.c \
+                      $(KERN_ARCH_SRC_DIR)/kdebug.c \
                       $(KERN_ARCH_SRC_DIR)/recip.S
 
index ff62f35..a2395fa 100644 (file)
@@ -36,7 +36,6 @@ static __inline uint32_t rcr3(void) __attribute__((always_inline));
 
 void print_cpuinfo(void);
 void show_mapping(uintptr_t start, size_t size);
-void backtrace(void);
 void cpu_halt(void);
 
 extern uintptr_t mmu_context_tables[MAX_NUM_CPUS][NCONTEXTS+CONTEXT_TABLE_PAD];
index 818b713..f5c516e 100644 (file)
@@ -82,55 +82,3 @@ void show_mapping(uintptr_t start, size_t size)
                        cprintf("%08p\n",0);
        }
 }
-
-void
-backtrace(void)
-{
-       int i = 0, j;
-
-       flush_windows();
-
-       cprintf("Backtrace:\n");
-
-       // hack: assumes (correctly) we aren't a leaf routine
-       void *sp, *pc, *newsp;
-       __asm__ __volatile__ ("mov %%sp,%0" : "=r"(sp));
-
-       assert(sp >= (void*)KERNBASE);
-
-       newsp = *((void**)sp+14);
-       pc = *((void**)sp+15);
-
-       cprintf("initial sp = %x, newsp = %x, pc = %x\n",sp,newsp,pc);
-       assert(newsp >= (void*)KERNBASE);
-
-       while(newsp)
-       {
-               cprintf("#%02d [<%x>]:\n",++i,pc);
-               cprintf("    %%sp: %x   Args:",newsp);
-               for(j = 8; j < 14; j++)
-                       cprintf(" %x",*((void**)sp+j));
-               cprintf("\n");
-
-               sp = newsp;
-
-               if(sp >= (void*)KERNBASE && (void**)sp+16 > ((void**)0+16))
-               {
-                       newsp = *((void**)sp+14);
-                       pc = *((void**)sp+15);
-               }
-               else if(current)
-               {
-                       error_t ret;
-                       ret  = memcpy_from_user(current,&newsp,(void**)sp+14,sizeof(void*));
-                       ret |= memcpy_from_user(current,&pc,(void**)sp+15,sizeof(void*));
-                       if(ret)
-                       {
-                               warn("Backtrace would have caused access exception; corrupt user stack?");
-                               break;
-                       }
-               }
-               else
-                       break;
-       }
-}
diff --git a/kern/arch/sparc/kdebug.c b/kern/arch/sparc/kdebug.c
new file mode 100644 (file)
index 0000000..60cc923
--- /dev/null
@@ -0,0 +1,71 @@
+#include <arch/sparc.h>
+#include <arch/arch.h>
+#include <arch/mmu.h>
+#include <stdio.h>
+#include <assert.h>
+#include <smp.h>
+#include <umem.h>
+#include <pmap.h>
+#include <kdebug.h>
+
+int debuginfo_eip(uintptr_t eip, struct eipdebuginfo *info)
+{
+       static bool once = TRUE;
+       if (once) {
+               warn("Not implemented for sparc");
+               once = FALSE;
+       }
+       return 0;
+}
+
+void backtrace(void)
+{
+       int i = 0, j;
+
+       flush_windows();
+
+       cprintf("Backtrace:\n");
+
+       // hack: assumes (correctly) we aren't a leaf routine
+       void *sp, *pc, *newsp;
+       __asm__ __volatile__ ("mov %%sp,%0" : "=r"(sp));
+
+       assert(sp >= (void*)KERNBASE);
+
+       newsp = *((void**)sp+14);
+       pc = *((void**)sp+15);
+
+       cprintf("initial sp = %x, newsp = %x, pc = %x\n",sp,newsp,pc);
+       assert(newsp >= (void*)KERNBASE);
+
+       while(newsp)
+       {
+               cprintf("#%02d [<%x>]:\n",++i,pc);
+               cprintf("    %%sp: %x   Args:",newsp);
+               for(j = 8; j < 14; j++)
+                       cprintf(" %x",*((void**)sp+j));
+               cprintf("\n");
+
+               sp = newsp;
+
+               if(sp >= (void*)KERNBASE && (void**)sp+16 > ((void**)0+16))
+               {
+                       newsp = *((void**)sp+14);
+                       pc = *((void**)sp+15);
+               }
+               else if(current)
+               {
+                       error_t ret;
+                       ret  = memcpy_from_user(current,&newsp,(void**)sp+14,sizeof(void*));
+                       ret |= memcpy_from_user(current,&pc,(void**)sp+15,sizeof(void*));
+                       if(ret)
+                       {
+                               warn("Backtrace would have caused access exception;"
+                                    "corrupt user stack?");
+                               break;
+                       }
+               }
+               else
+                       break;
+       }
+}
diff --git a/kern/arch/sparc/kdebug.h b/kern/arch/sparc/kdebug.h
new file mode 100644 (file)
index 0000000..3ac5c5f
--- /dev/null
@@ -0,0 +1,25 @@
+/* Copyright (c) 2011 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Sparc-specific Kernel debugging headers and static inlines */
+
+#ifndef ROS_KERN_ARCH_KDEBUG_H
+#define ROS_KERN_ARCH_KDEBUG_H
+
+#include <ros/common.h>
+#include <assert.h>
+
+/* Returns a PC/EIP in the function that called us, preferably near the call
+ * site. */
+static inline uintptr_t get_caller_pc(void)
+{
+       static bool once = TRUE;
+       if (once) {
+               warn("Not implemented for sparc");
+               once = FALSE;
+       }
+       return 0;
+}
+
+#endif /* ROS_KERN_ARCH_KDEBUG_H */
index 1c4519d..13746a1 100644 (file)
@@ -13,6 +13,7 @@
 #include <ros/mman.h>
 #include <umem.h>
 #include <pmap.h>
+#include <kdebug.h>
 
 #ifdef __SHARC__
 #pragma nosharc
index 2e49fa6..a6b7613 100644 (file)
@@ -2,13 +2,14 @@
 #define ROS_KERN_KDEBUG_H
 
 #include <ros/common.h>
+#include <arch/kdebug.h>
 
 // Debug information about a particular instruction pointer
-typedef struct Eipdebuginfo {
-       const char *NTS eip_file;               // Source code filename for EIP
+typedef struct eipdebuginfo {
+       const char *eip_file;           // Source code filename for EIP
        int eip_line;                           // Source code linenumber for EIP
 
-       const char *NT COUNT(eip_fn_namelen) eip_fn_name;       // Name of function containing EIP
+       const char *eip_fn_name;        // Name of function containing EIP
                                                                //  - Note: not null terminated!
        int eip_fn_namelen;                     // Length of function name
        uintptr_t eip_fn_addr;          // Address of start of function
@@ -17,5 +18,13 @@ typedef struct Eipdebuginfo {
 
 int debuginfo_eip(uintptr_t eip, eipdebuginfo_t *NONNULL info);
 void *debug_get_fn_addr(char *fn_name);
+void backtrace(void);
 
-#endif
+/* Arch dependent, listed here for ease-of-use */
+static inline uintptr_t get_caller_pc(void);
+
+/* Returns a null-terminated string with the function name for a given PC /
+ * instruction pointer.  kfree() the result. */
+char *get_fn_name(uintptr_t pc);
+
+#endif /* ROS_KERN_KDEBUG_H */
index 22307d0..c4db827 100644 (file)
@@ -53,6 +53,7 @@ KERN_SRCFILES := $(KERN_ARCH_SRCFILES) \
                  $(KERN_SRC_DIR)/net.c \
                  $(KERN_SRC_DIR)/event.c \
                  $(KERN_SRC_DIR)/alarm.c \
+                 $(KERN_SRC_DIR)/kdebug.c \
                  $(KERN_SRC_DIR)/arsc.c
 
 # Only build files if they exist.
diff --git a/kern/src/kdebug.c b/kern/src/kdebug.c
new file mode 100644 (file)
index 0000000..26fc430
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (c) 2011 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Arch-independent kernel debugging */
+
+#include <kdebug.h>
+#include <kmalloc.h>
+#include <string.h>
+#include <assert.h>
+
+/* Returns a null-terminated string with the function name for a given PC /
+ * instruction pointer.  kfree() the result. */
+char *get_fn_name(uintptr_t pc)
+{
+       struct eipdebuginfo debuginfo;
+       char *buf;
+       if (debuginfo_eip(pc, &debuginfo))
+               return 0;
+       buf = kmalloc(debuginfo.eip_fn_namelen + 1, 0);
+       if (!buf)
+               return 0;
+       assert(debuginfo.eip_fn_name);
+       strncpy(buf, debuginfo.eip_fn_name, debuginfo.eip_fn_namelen);
+       buf[debuginfo.eip_fn_namelen] = 0;
+       return buf;
+}