Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / ppc / xmon / xmon.c
index 8565f49..06fa44b 100644 (file)
@@ -9,15 +9,11 @@
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
+#include <linux/kallsyms.h>
 #include <asm/ptrace.h>
 #include <asm/string.h>
-#include <asm/prom.h>
-#include <asm/bootx.h>
 #include <asm/machdep.h>
 #include <asm/xmon.h>
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
 #include "nonstdio.h"
 #include "privinst.h"
 
@@ -93,21 +89,16 @@ static void take_input(char *);
 static unsigned read_spr(int);
 static void write_spr(int, unsigned);
 static void super_regs(void);
-static void print_sysmap(void);
-static void sysmap_lookup(void);
+static void symbol_lookup(void);
 static void remove_bpts(void);
 static void insert_bpts(void);
 static struct bpt *at_breakpoint(unsigned pc);
 static void bpt_cmds(void);
-static void cacheflush(void);
+void cacheflush(void);
 #ifdef CONFIG_SMP
 static void cpu_cmd(void);
 #endif /* CONFIG_SMP */
-static int pretty_print_addr(unsigned long addr);
 static void csum(void);
-#ifdef CONFIG_BOOTX_TEXT
-static void vidcmds(void);
-#endif
 static void bootcmds(void);
 static void proccall(void);
 static void printtime(void);
@@ -120,8 +111,6 @@ extern void longjmp(u_int *, int);
 
 extern void xmon_enter(void);
 extern void xmon_leave(void);
-extern char* xmon_find_symbol(unsigned long addr, unsigned long* saddr);
-extern unsigned long xmon_symbol_to_addr(char* symbol);
 
 static unsigned start_tb[NR_CPUS][2];
 static unsigned stop_tb[NR_CPUS][2];
@@ -148,13 +137,17 @@ Commands:\n\
   mm   move a block of memory\n\
   ms   set a block of memory\n\
   md   compare two blocks of memory\n\
-  M    print System.map\n\
   r    print registers\n\
   S    print special registers\n\
   t    print backtrace\n\
-  la   lookup address in system.map\n\
-  ls   lookup symbol in system.map\n\
+  la   lookup address\n\
+  ls   lookup symbol\n\
+  C    checksum\n\
+  p    call function with arguments\n\
+  T    print time\n\
   x    exit monitor\n\
+  zr    reboot\n\
+  zh    halt\n\
 ";
 
 static int xmon_trace[NR_CPUS];
@@ -175,6 +168,35 @@ extern inline void __delay(unsigned int loops)
                                     "r" (loops) : "ctr");
 }
 
+/* Print an address in numeric and symbolic form (if possible) */
+static void xmon_print_symbol(unsigned long address, const char *mid,
+                             const char *after)
+{
+       char *modname;
+       const char *name = NULL;
+       unsigned long offset, size;
+       static char tmpstr[128];
+
+       printf("%.8lx", address);
+       if (setjmp(bus_error_jmp) == 0) {
+               debugger_fault_handler = handle_fault;
+               sync();
+               name = kallsyms_lookup(address, &size, &offset, &modname,
+                                      tmpstr);
+               sync();
+               /* wait a little while to see if we get a machine check */
+               __delay(200);
+       }
+       debugger_fault_handler = NULL;
+
+       if (name) {
+               printf("%s%s+%#lx/%#lx", mid, name, offset, size);
+               if (modname)
+                       printf(" [%s]", modname);
+       }
+       printf("%s", after);
+}
+
 static void get_tb(unsigned *p)
 {
        unsigned hi, lo, hiagain;
@@ -190,8 +212,7 @@ static void get_tb(unsigned *p)
        p[1] = lo;
 }
 
-void
-xmon(struct pt_regs *excp)
+int xmon(struct pt_regs *excp)
 {
        struct pt_regs regs;
        int msr, cmd;
@@ -231,16 +252,6 @@ xmon(struct pt_regs *excp)
         */
 #endif /* CONFIG_SMP */
        remove_bpts();
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if( setjmp(bus_error_jmp) == 0 ) {
-               debugger_fault_handler = handle_fault;
-               sync();
-               set_backlight_enable(1);
-               set_backlight_level(BACKLIGHT_MAX);
-               sync();
-       }
-       debugger_fault_handler = NULL;
-#endif /* CONFIG_PMAC_BACKLIGHT */
        cmd = cmds(excp);
        if (cmd == 's') {
                xmon_trace[smp_processor_id()] = SSTEP;
@@ -260,6 +271,8 @@ xmon(struct pt_regs *excp)
 #endif /* CONFIG_SMP */
        set_msr(msr);           /* restore interrupt enable */
        get_tb(start_tb[smp_processor_id()]);
+
+       return cmd != 'X';
 }
 
 irqreturn_t
@@ -454,7 +467,7 @@ cmds(struct pt_regs *excp)
                        dump();
                        break;
                case 'l':
-                       sysmap_lookup();
+                       symbol_lookup();
                        break;
                case 'r':
                        if (excp != NULL)
@@ -466,9 +479,6 @@ cmds(struct pt_regs *excp)
                        else
                                excprint(excp);
                        break;
-               case 'M':
-                       print_sysmap();
-                       break;
                case 'S':
                        super_regs();
                        break;
@@ -507,11 +517,6 @@ cmds(struct pt_regs *excp)
                        cpu_cmd();
                        break;
 #endif /* CONFIG_SMP */
-#ifdef CONFIG_BOOTX_TEXT
-               case 'v':
-                       vidcmds();
-                       break;
-#endif
                case 'z':
                        bootcmds();
                        break;
@@ -603,43 +608,6 @@ static void cpu_cmd(void)
 }
 #endif /* CONFIG_SMP */
 
-#ifdef CONFIG_BOOTX_TEXT
-extern boot_infos_t disp_bi;
-
-static void vidcmds(void)
-{
-       int c = inchar();
-       unsigned int val, w;
-       extern int boot_text_mapped;
-
-       if (!boot_text_mapped)
-               return;
-       if (c != '\n' && scanhex(&val)) {
-               switch (c) {
-               case 'd':
-                       w = disp_bi.dispDeviceRowBytes
-                               / (disp_bi.dispDeviceDepth >> 3);
-                       disp_bi.dispDeviceDepth = val;
-                       disp_bi.dispDeviceRowBytes = w * (val >> 3);
-                       return;
-               case 'p':
-                       disp_bi.dispDeviceRowBytes = val;
-                       return;
-               case 'w':
-                       disp_bi.dispDeviceRect[2] = val;
-                       return;
-               case 'h':
-                       disp_bi.dispDeviceRect[3] = val;
-                       return;
-               }
-       }
-       printf("W = %d (0x%x) H = %d (0x%x) D = %d (0x%x) P = %d (0x%x)\n",
-              disp_bi.dispDeviceRect[2], disp_bi.dispDeviceRect[2],
-              disp_bi.dispDeviceRect[3], disp_bi.dispDeviceRect[3],
-              disp_bi.dispDeviceDepth, disp_bi.dispDeviceDepth,
-              disp_bi.dispDeviceRowBytes, disp_bi.dispDeviceRowBytes);
-}
-#endif /* CONFIG_BOOTX_TEXT */
 
 static unsigned short fcstab[256] = {
        0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
@@ -825,20 +793,19 @@ backtrace(struct pt_regs *excp)
        for (; sp != 0; sp = stack[0]) {
                if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
                        break;
-               pretty_print_addr(stack[1]);
-               printf(" ");
+               printf("[%.8lx] ", stack);
+               xmon_print_symbol(stack[1], " ", "\n");
                if (stack[1] == (unsigned) &ret_from_except
                    || stack[1] == (unsigned) &ret_from_except_full
                    || stack[1] == (unsigned) &ret_from_syscall) {
                        if (mread(sp+16, &regs, sizeof(regs)) != sizeof(regs))
                                break;
-                       printf("\nexception:%x [%x] %x ", regs.trap, sp+16,
+                       printf("exception:%x [%x] %x\n", regs.trap, sp+16,
                               regs.nip);
                        sp = regs.gpr[1];
                        if (mread(sp, stack, sizeof(stack)) != sizeof(stack))
                                break;
                }
-               printf("\n");
        }
 }
 
@@ -859,11 +826,10 @@ excprint(struct pt_regs *fp)
 #ifdef CONFIG_SMP
        printf("cpu %d: ", smp_processor_id());
 #endif /* CONFIG_SMP */
-       printf("vector: %x at pc = ", fp->trap);
-       pretty_print_addr(fp->nip);
-       printf(", lr = ");
-       pretty_print_addr(fp->link);
-       printf("\nmsr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp);
+       printf("vector: %x at pc=", fp->trap);
+       xmon_print_symbol(fp->nip, ": ", ", lr=");
+       xmon_print_symbol(fp->link, ": ", "\n");
+       printf("msr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp);
        trap = TRAP(fp);
        if (trap == 0x300 || trap == 0x600)
                printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr);
@@ -950,24 +916,6 @@ static unsigned int regno;
 extern char exc_prolog;
 extern char dec_exc;
 
-void
-print_sysmap(void)
-{
-       extern char *sysmap;
-       if ( sysmap ) {
-               printf("System.map: \n");
-               if( setjmp(bus_error_jmp) == 0 ) {
-                       debugger_fault_handler = handle_fault;
-                       sync();
-                       xmon_puts(sysmap);
-                       sync();
-               }
-               debugger_fault_handler = NULL;
-       }
-       else
-               printf("No System.map\n");
-}
-
 void
 super_regs(void)
 {
@@ -1025,7 +973,6 @@ dump_hash_table(void)
 }
 #else
 
-#ifndef CONFIG_PPC64BRIDGE
 static void
 dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
 {
@@ -1084,66 +1031,6 @@ dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
                printf(" ... %x\n", last_va);
 }
 
-#else /* CONFIG_PPC64BRIDGE */
-static void
-dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
-{
-       extern void *Hash;
-       extern unsigned long Hash_size;
-       unsigned *htab = Hash;
-       unsigned hsize = Hash_size;
-       unsigned v, hmask, va, last_va;
-       int found, last_found, i;
-       unsigned *hg, w1, last_w2, last_va0;
-
-       last_found = 0;
-       hmask = hsize / 128 - 1;
-       va = start;
-       start = (start >> 12) & 0xffff;
-       end = (end >> 12) & 0xffff;
-       for (v = start; v < end; ++v) {
-               found = 0;
-               hg = htab + (((v ^ seg) & hmask) * 32);
-               w1 = 1 | (seg << 12) | ((v & 0xf800) >> 4);
-               for (i = 0; i < 8; ++i, hg += 4) {
-                       if (hg[1] == w1) {
-                               found = 1;
-                               break;
-                       }
-               }
-               if (!found) {
-                       w1 ^= 2;
-                       hg = htab + ((~(v ^ seg) & hmask) * 32);
-                       for (i = 0; i < 8; ++i, hg += 4) {
-                               if (hg[1] == w1) {
-                                       found = 1;
-                                       break;
-                               }
-                       }
-               }
-               if (!(last_found && found && (hg[3] & ~0x180) == last_w2 + 4096)) {
-                       if (last_found) {
-                               if (last_va != last_va0)
-                                       printf(" ... %x", last_va);
-                               printf("\n");
-                       }
-                       if (found) {
-                               printf("%x to %x", va, hg[3]);
-                               last_va0 = va;
-                       }
-                       last_found = found;
-               }
-               if (found) {
-                       last_w2 = hg[3] & ~0x180;
-                       last_va = va;
-               }
-               va += 4096;
-       }
-       if (last_found)
-               printf(" ... %x\n", last_va);
-}
-#endif /* CONFIG_PPC64BRIDGE */
-
 static unsigned hash_ctx;
 static unsigned hash_start;
 static unsigned hash_end;
@@ -1738,7 +1625,7 @@ scanhex(unsigned *vp)
                printf("invalid register name '%%%s'\n", regname);
                return 0;
        } else if (c == '$') {
-               static char symname[64];
+               static char symname[128];
                int i;
                for (i=0; i<63; i++) {
                        c = inchar();
@@ -1749,7 +1636,14 @@ scanhex(unsigned *vp)
                        symname[i] = c;
                }
                symname[i++] = 0;
-               *vp = xmon_symbol_to_addr(symname);
+               *vp = 0;
+               if (setjmp(bus_error_jmp) == 0) {
+                       debugger_fault_handler = handle_fault;
+                       sync();
+                       *vp = kallsyms_lookup_name(symname);
+                       sync();
+               }
+               debugger_fault_handler = NULL;
                if (!(*vp)) {
                        printf("unknown symbol\n");
                        return 0;
@@ -1840,169 +1734,34 @@ take_input(char *str)
        lineptr = str;
 }
 
-void
-sysmap_lookup(void)
+static void
+symbol_lookup(void)
 {
        int type = inchar();
        unsigned addr;
-       static char tmp[64];
-       char* cur;
+       static char tmp[128];
 
-       extern char *sysmap;
-       extern unsigned long sysmap_size;
-       if ( !sysmap || !sysmap_size )
-               return;
-
-       switch(type) {
-               case 'a':
-                       if (scanhex(&addr)) {
-                               pretty_print_addr(addr);
-                               printf("\n");
-                       }
-                       termch = 0;
-                       break;
-               case 's':
-                       getstring(tmp, 64);
-                       if( setjmp(bus_error_jmp) == 0 ) {
-                               debugger_fault_handler = handle_fault;
-                               sync();
-                               cur = sysmap;
-                               do {
-                                       cur = strstr(cur, tmp);
-                                       if (cur) {
-                                               static char res[64];
-                                               char *p, *d;
-                                               p = cur;
-                                               while(p > sysmap && *p != 10)
-                                                       p--;
-                                               if (*p == 10) p++;
-                                               d = res;
-                                               while(*p && p < (sysmap + sysmap_size) && *p != 10)
-                                                       *(d++) = *(p++);
-                                               *(d++) = 0;
-                                               printf("%s\n", res);
-                                               cur++;
-                                       }
-                               } while (cur);
-                               sync();
-                       }
-                       debugger_fault_handler = NULL;
-                       termch = 0;
-                       break;
-       }
-}
-
-static int
-pretty_print_addr(unsigned long addr)
-{
-       char *sym;
-       unsigned long saddr;
-       
-       printf("%08x", addr);
-       sym = xmon_find_symbol(addr, &saddr);
-       if (sym)
-               printf(" (%s+0x%x)", sym, addr-saddr);
-       return (sym != 0);
-}
-
-char*
-xmon_find_symbol(unsigned long addr, unsigned long* saddr)
-{
-       static char rbuffer[64];
-       char *p, *ep, *limit;
-       unsigned long prev, next;
-       char* psym;
-
-       extern char *sysmap;
-       extern unsigned long sysmap_size;
-       if ( !sysmap || !sysmap_size )
-               return NULL;
-       
-       prev = 0;
-       psym = NULL;
-       p = sysmap;
-       limit = p + sysmap_size;
-       if( setjmp(bus_error_jmp) == 0 ) {
-               debugger_fault_handler = handle_fault;
-               sync();
-               do {
-                       next = simple_strtoul(p, &p, 16);
-                       if (next > addr && prev <= addr) {
-                               if (!psym)
-                                       goto bail;
-                               ep = rbuffer;
-                               p = psym;
-                               while(*p && p < limit && *p == 32)
-                                       p++;
-                               while(*p && p < limit && *p != 10 && (ep - rbuffer) < 63)
-                                       *(ep++) = *(p++);
-                               *(ep++) = 0;
-                               if (saddr)
-                                       *saddr = prev;
-                               debugger_fault_handler = NULL;
-                               return rbuffer;
-                       }
-                       prev = next;
-                       psym = p;
-                       while(*p && p < limit && *p != 10)
-                               p++;
-                       if (*p) p++;
-               } while(*p && p < limit && next);
-bail:
-               sync();
+       switch (type) {
+       case 'a':
+               if (scanhex(&addr))
+                       xmon_print_symbol(addr, ": ", "\n");
+               termch = 0;
+               break;
+       case 's':
+               getstring(tmp, 64);
+               if (setjmp(bus_error_jmp) == 0) {
+                       debugger_fault_handler = handle_fault;
+                       sync();
+                       addr = kallsyms_lookup_name(tmp);
+                       if (addr)
+                               printf("%s: %lx\n", tmp, addr);
+                       else
+                               printf("Symbol '%s' not found.\n", tmp);
+                       sync();
+               }
+               debugger_fault_handler = NULL;
+               termch = 0;
+               break;
        }
-       debugger_fault_handler = NULL;
-       return NULL;
 }
 
-unsigned long
-xmon_symbol_to_addr(char* symbol)
-{
-       char *p, *cur;
-       char *match = NULL;
-       int goodness = 0;
-       int result = 0;
-       
-       extern char *sysmap;
-       extern unsigned long sysmap_size;
-       if ( !sysmap || !sysmap_size )
-               return 0;
-
-       if( setjmp(bus_error_jmp) == 0 ) {
-               debugger_fault_handler = handle_fault;
-               sync();
-               cur = sysmap;
-               while(cur) {
-                       cur = strstr(cur, symbol);
-                       if (cur) {
-                               int gd = 1;
-
-                               /* best match if equal, better match if
-                                * begins with
-                                */
-                               if (cur == sysmap || *(cur-1) == ' ') {
-                                       gd++;
-                                       if (cur[strlen(symbol)] == 10)
-                                               gd++;
-                               }
-                               if (gd > goodness) {
-                                       match = cur;
-                                       goodness = gd;
-                                       if (gd == 3)
-                                               break;
-                               }
-                               cur++;
-                       }
-               }       
-               if (goodness) {
-                       p = match;
-                       while(p > sysmap && *p != 10)
-                               p--;
-                       if (*p == 10) p++;
-                       result = simple_strtoul(p, &p, 16);
-               }
-               sync();
-       }
-       debugger_fault_handler = NULL;
-       return result;
-}