diff options
Diffstat (limited to 'arch/ppc/xmon/xmon.c')
-rw-r--r-- | arch/ppc/xmon/xmon.c | 270 |
1 files changed, 72 insertions, 198 deletions
diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index 8565f49b8b0b..be7869e39465 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/smp.h> | 9 | #include <linux/smp.h> |
10 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
11 | #include <linux/bitops.h> | 11 | #include <linux/bitops.h> |
12 | #include <linux/kallsyms.h> | ||
12 | #include <asm/ptrace.h> | 13 | #include <asm/ptrace.h> |
13 | #include <asm/string.h> | 14 | #include <asm/string.h> |
14 | #include <asm/prom.h> | 15 | #include <asm/prom.h> |
@@ -93,8 +94,7 @@ static void take_input(char *); | |||
93 | static unsigned read_spr(int); | 94 | static unsigned read_spr(int); |
94 | static void write_spr(int, unsigned); | 95 | static void write_spr(int, unsigned); |
95 | static void super_regs(void); | 96 | static void super_regs(void); |
96 | static void print_sysmap(void); | 97 | static void symbol_lookup(void); |
97 | static void sysmap_lookup(void); | ||
98 | static void remove_bpts(void); | 98 | static void remove_bpts(void); |
99 | static void insert_bpts(void); | 99 | static void insert_bpts(void); |
100 | static struct bpt *at_breakpoint(unsigned pc); | 100 | static struct bpt *at_breakpoint(unsigned pc); |
@@ -103,7 +103,6 @@ static void cacheflush(void); | |||
103 | #ifdef CONFIG_SMP | 103 | #ifdef CONFIG_SMP |
104 | static void cpu_cmd(void); | 104 | static void cpu_cmd(void); |
105 | #endif /* CONFIG_SMP */ | 105 | #endif /* CONFIG_SMP */ |
106 | static int pretty_print_addr(unsigned long addr); | ||
107 | static void csum(void); | 106 | static void csum(void); |
108 | #ifdef CONFIG_BOOTX_TEXT | 107 | #ifdef CONFIG_BOOTX_TEXT |
109 | static void vidcmds(void); | 108 | static void vidcmds(void); |
@@ -120,8 +119,6 @@ extern void longjmp(u_int *, int); | |||
120 | 119 | ||
121 | extern void xmon_enter(void); | 120 | extern void xmon_enter(void); |
122 | extern void xmon_leave(void); | 121 | extern void xmon_leave(void); |
123 | extern char* xmon_find_symbol(unsigned long addr, unsigned long* saddr); | ||
124 | extern unsigned long xmon_symbol_to_addr(char* symbol); | ||
125 | 122 | ||
126 | static unsigned start_tb[NR_CPUS][2]; | 123 | static unsigned start_tb[NR_CPUS][2]; |
127 | static unsigned stop_tb[NR_CPUS][2]; | 124 | static unsigned stop_tb[NR_CPUS][2]; |
@@ -148,7 +145,6 @@ Commands:\n\ | |||
148 | mm move a block of memory\n\ | 145 | mm move a block of memory\n\ |
149 | ms set a block of memory\n\ | 146 | ms set a block of memory\n\ |
150 | md compare two blocks of memory\n\ | 147 | md compare two blocks of memory\n\ |
151 | M print System.map\n\ | ||
152 | r print registers\n\ | 148 | r print registers\n\ |
153 | S print special registers\n\ | 149 | S print special registers\n\ |
154 | t print backtrace\n\ | 150 | t print backtrace\n\ |
@@ -175,6 +171,35 @@ extern inline void __delay(unsigned int loops) | |||
175 | "r" (loops) : "ctr"); | 171 | "r" (loops) : "ctr"); |
176 | } | 172 | } |
177 | 173 | ||
174 | /* Print an address in numeric and symbolic form (if possible) */ | ||
175 | static void xmon_print_symbol(unsigned long address, const char *mid, | ||
176 | const char *after) | ||
177 | { | ||
178 | char *modname; | ||
179 | const char *name = NULL; | ||
180 | unsigned long offset, size; | ||
181 | static char tmpstr[128]; | ||
182 | |||
183 | printf("%.8lx", address); | ||
184 | if (setjmp(bus_error_jmp) == 0) { | ||
185 | debugger_fault_handler = handle_fault; | ||
186 | sync(); | ||
187 | name = kallsyms_lookup(address, &size, &offset, &modname, | ||
188 | tmpstr); | ||
189 | sync(); | ||
190 | /* wait a little while to see if we get a machine check */ | ||
191 | __delay(200); | ||
192 | } | ||
193 | debugger_fault_handler = NULL; | ||
194 | |||
195 | if (name) { | ||
196 | printf("%s%s+%#lx/%#lx", mid, name, offset, size); | ||
197 | if (modname) | ||
198 | printf(" [%s]", modname); | ||
199 | } | ||
200 | printf("%s", after); | ||
201 | } | ||
202 | |||
178 | static void get_tb(unsigned *p) | 203 | static void get_tb(unsigned *p) |
179 | { | 204 | { |
180 | unsigned hi, lo, hiagain; | 205 | unsigned hi, lo, hiagain; |
@@ -454,7 +479,7 @@ cmds(struct pt_regs *excp) | |||
454 | dump(); | 479 | dump(); |
455 | break; | 480 | break; |
456 | case 'l': | 481 | case 'l': |
457 | sysmap_lookup(); | 482 | symbol_lookup(); |
458 | break; | 483 | break; |
459 | case 'r': | 484 | case 'r': |
460 | if (excp != NULL) | 485 | if (excp != NULL) |
@@ -466,9 +491,6 @@ cmds(struct pt_regs *excp) | |||
466 | else | 491 | else |
467 | excprint(excp); | 492 | excprint(excp); |
468 | break; | 493 | break; |
469 | case 'M': | ||
470 | print_sysmap(); | ||
471 | break; | ||
472 | case 'S': | 494 | case 'S': |
473 | super_regs(); | 495 | super_regs(); |
474 | break; | 496 | break; |
@@ -825,20 +847,19 @@ backtrace(struct pt_regs *excp) | |||
825 | for (; sp != 0; sp = stack[0]) { | 847 | for (; sp != 0; sp = stack[0]) { |
826 | if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) | 848 | if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) |
827 | break; | 849 | break; |
828 | pretty_print_addr(stack[1]); | 850 | printf("[%.8lx] ", stack); |
829 | printf(" "); | 851 | xmon_print_symbol(stack[1], " ", "\n"); |
830 | if (stack[1] == (unsigned) &ret_from_except | 852 | if (stack[1] == (unsigned) &ret_from_except |
831 | || stack[1] == (unsigned) &ret_from_except_full | 853 | || stack[1] == (unsigned) &ret_from_except_full |
832 | || stack[1] == (unsigned) &ret_from_syscall) { | 854 | || stack[1] == (unsigned) &ret_from_syscall) { |
833 | if (mread(sp+16, ®s, sizeof(regs)) != sizeof(regs)) | 855 | if (mread(sp+16, ®s, sizeof(regs)) != sizeof(regs)) |
834 | break; | 856 | break; |
835 | printf("\nexception:%x [%x] %x ", regs.trap, sp+16, | 857 | printf("exception:%x [%x] %x\n", regs.trap, sp+16, |
836 | regs.nip); | 858 | regs.nip); |
837 | sp = regs.gpr[1]; | 859 | sp = regs.gpr[1]; |
838 | if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) | 860 | if (mread(sp, stack, sizeof(stack)) != sizeof(stack)) |
839 | break; | 861 | break; |
840 | } | 862 | } |
841 | printf("\n"); | ||
842 | } | 863 | } |
843 | } | 864 | } |
844 | 865 | ||
@@ -859,11 +880,10 @@ excprint(struct pt_regs *fp) | |||
859 | #ifdef CONFIG_SMP | 880 | #ifdef CONFIG_SMP |
860 | printf("cpu %d: ", smp_processor_id()); | 881 | printf("cpu %d: ", smp_processor_id()); |
861 | #endif /* CONFIG_SMP */ | 882 | #endif /* CONFIG_SMP */ |
862 | printf("vector: %x at pc = ", fp->trap); | 883 | printf("vector: %x at pc=", fp->trap); |
863 | pretty_print_addr(fp->nip); | 884 | xmon_print_symbol(fp->nip, ": ", ", lr="); |
864 | printf(", lr = "); | 885 | xmon_print_symbol(fp->link, ": ", "\n"); |
865 | pretty_print_addr(fp->link); | 886 | printf("msr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp); |
866 | printf("\nmsr = %x, sp = %x [%x]\n", fp->msr, fp->gpr[1], fp); | ||
867 | trap = TRAP(fp); | 887 | trap = TRAP(fp); |
868 | if (trap == 0x300 || trap == 0x600) | 888 | if (trap == 0x300 || trap == 0x600) |
869 | printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr); | 889 | printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr); |
@@ -951,24 +971,6 @@ extern char exc_prolog; | |||
951 | extern char dec_exc; | 971 | extern char dec_exc; |
952 | 972 | ||
953 | void | 973 | void |
954 | print_sysmap(void) | ||
955 | { | ||
956 | extern char *sysmap; | ||
957 | if ( sysmap ) { | ||
958 | printf("System.map: \n"); | ||
959 | if( setjmp(bus_error_jmp) == 0 ) { | ||
960 | debugger_fault_handler = handle_fault; | ||
961 | sync(); | ||
962 | xmon_puts(sysmap); | ||
963 | sync(); | ||
964 | } | ||
965 | debugger_fault_handler = NULL; | ||
966 | } | ||
967 | else | ||
968 | printf("No System.map\n"); | ||
969 | } | ||
970 | |||
971 | void | ||
972 | super_regs(void) | 974 | super_regs(void) |
973 | { | 975 | { |
974 | int i, cmd; | 976 | int i, cmd; |
@@ -1738,7 +1740,7 @@ scanhex(unsigned *vp) | |||
1738 | printf("invalid register name '%%%s'\n", regname); | 1740 | printf("invalid register name '%%%s'\n", regname); |
1739 | return 0; | 1741 | return 0; |
1740 | } else if (c == '$') { | 1742 | } else if (c == '$') { |
1741 | static char symname[64]; | 1743 | static char symname[128]; |
1742 | int i; | 1744 | int i; |
1743 | for (i=0; i<63; i++) { | 1745 | for (i=0; i<63; i++) { |
1744 | c = inchar(); | 1746 | c = inchar(); |
@@ -1749,7 +1751,14 @@ scanhex(unsigned *vp) | |||
1749 | symname[i] = c; | 1751 | symname[i] = c; |
1750 | } | 1752 | } |
1751 | symname[i++] = 0; | 1753 | symname[i++] = 0; |
1752 | *vp = xmon_symbol_to_addr(symname); | 1754 | *vp = 0; |
1755 | if (setjmp(bus_error_jmp) == 0) { | ||
1756 | debugger_fault_handler = handle_fault; | ||
1757 | sync(); | ||
1758 | *vp = kallsyms_lookup_name(symname); | ||
1759 | sync(); | ||
1760 | } | ||
1761 | debugger_fault_handler = NULL; | ||
1753 | if (!(*vp)) { | 1762 | if (!(*vp)) { |
1754 | printf("unknown symbol\n"); | 1763 | printf("unknown symbol\n"); |
1755 | return 0; | 1764 | return 0; |
@@ -1840,169 +1849,34 @@ take_input(char *str) | |||
1840 | lineptr = str; | 1849 | lineptr = str; |
1841 | } | 1850 | } |
1842 | 1851 | ||
1843 | void | 1852 | static void |
1844 | sysmap_lookup(void) | 1853 | symbol_lookup(void) |
1845 | { | 1854 | { |
1846 | int type = inchar(); | 1855 | int type = inchar(); |
1847 | unsigned addr; | 1856 | unsigned addr; |
1848 | static char tmp[64]; | 1857 | static char tmp[128]; |
1849 | char* cur; | ||
1850 | |||
1851 | extern char *sysmap; | ||
1852 | extern unsigned long sysmap_size; | ||
1853 | if ( !sysmap || !sysmap_size ) | ||
1854 | return; | ||
1855 | |||
1856 | switch(type) { | ||
1857 | case 'a': | ||
1858 | if (scanhex(&addr)) { | ||
1859 | pretty_print_addr(addr); | ||
1860 | printf("\n"); | ||
1861 | } | ||
1862 | termch = 0; | ||
1863 | break; | ||
1864 | case 's': | ||
1865 | getstring(tmp, 64); | ||
1866 | if( setjmp(bus_error_jmp) == 0 ) { | ||
1867 | debugger_fault_handler = handle_fault; | ||
1868 | sync(); | ||
1869 | cur = sysmap; | ||
1870 | do { | ||
1871 | cur = strstr(cur, tmp); | ||
1872 | if (cur) { | ||
1873 | static char res[64]; | ||
1874 | char *p, *d; | ||
1875 | p = cur; | ||
1876 | while(p > sysmap && *p != 10) | ||
1877 | p--; | ||
1878 | if (*p == 10) p++; | ||
1879 | d = res; | ||
1880 | while(*p && p < (sysmap + sysmap_size) && *p != 10) | ||
1881 | *(d++) = *(p++); | ||
1882 | *(d++) = 0; | ||
1883 | printf("%s\n", res); | ||
1884 | cur++; | ||
1885 | } | ||
1886 | } while (cur); | ||
1887 | sync(); | ||
1888 | } | ||
1889 | debugger_fault_handler = NULL; | ||
1890 | termch = 0; | ||
1891 | break; | ||
1892 | } | ||
1893 | } | ||
1894 | 1858 | ||
1895 | static int | 1859 | switch (type) { |
1896 | pretty_print_addr(unsigned long addr) | 1860 | case 'a': |
1897 | { | 1861 | if (scanhex(&addr)) |
1898 | char *sym; | 1862 | xmon_print_symbol(addr, ": ", "\n"); |
1899 | unsigned long saddr; | 1863 | termch = 0; |
1900 | 1864 | break; | |
1901 | printf("%08x", addr); | 1865 | case 's': |
1902 | sym = xmon_find_symbol(addr, &saddr); | 1866 | getstring(tmp, 64); |
1903 | if (sym) | 1867 | if (setjmp(bus_error_jmp) == 0) { |
1904 | printf(" (%s+0x%x)", sym, addr-saddr); | 1868 | debugger_fault_handler = handle_fault; |
1905 | return (sym != 0); | 1869 | sync(); |
1906 | } | 1870 | addr = kallsyms_lookup_name(tmp); |
1907 | 1871 | if (addr) | |
1908 | char* | 1872 | printf("%s: %lx\n", tmp, addr); |
1909 | xmon_find_symbol(unsigned long addr, unsigned long* saddr) | 1873 | else |
1910 | { | 1874 | printf("Symbol '%s' not found.\n", tmp); |
1911 | static char rbuffer[64]; | 1875 | sync(); |
1912 | char *p, *ep, *limit; | 1876 | } |
1913 | unsigned long prev, next; | 1877 | debugger_fault_handler = NULL; |
1914 | char* psym; | 1878 | termch = 0; |
1915 | 1879 | break; | |
1916 | extern char *sysmap; | ||
1917 | extern unsigned long sysmap_size; | ||
1918 | if ( !sysmap || !sysmap_size ) | ||
1919 | return NULL; | ||
1920 | |||
1921 | prev = 0; | ||
1922 | psym = NULL; | ||
1923 | p = sysmap; | ||
1924 | limit = p + sysmap_size; | ||
1925 | if( setjmp(bus_error_jmp) == 0 ) { | ||
1926 | debugger_fault_handler = handle_fault; | ||
1927 | sync(); | ||
1928 | do { | ||
1929 | next = simple_strtoul(p, &p, 16); | ||
1930 | if (next > addr && prev <= addr) { | ||
1931 | if (!psym) | ||
1932 | goto bail; | ||
1933 | ep = rbuffer; | ||
1934 | p = psym; | ||
1935 | while(*p && p < limit && *p == 32) | ||
1936 | p++; | ||
1937 | while(*p && p < limit && *p != 10 && (ep - rbuffer) < 63) | ||
1938 | *(ep++) = *(p++); | ||
1939 | *(ep++) = 0; | ||
1940 | if (saddr) | ||
1941 | *saddr = prev; | ||
1942 | debugger_fault_handler = NULL; | ||
1943 | return rbuffer; | ||
1944 | } | ||
1945 | prev = next; | ||
1946 | psym = p; | ||
1947 | while(*p && p < limit && *p != 10) | ||
1948 | p++; | ||
1949 | if (*p) p++; | ||
1950 | } while(*p && p < limit && next); | ||
1951 | bail: | ||
1952 | sync(); | ||
1953 | } | 1880 | } |
1954 | debugger_fault_handler = NULL; | ||
1955 | return NULL; | ||
1956 | } | 1881 | } |
1957 | 1882 | ||
1958 | unsigned long | ||
1959 | xmon_symbol_to_addr(char* symbol) | ||
1960 | { | ||
1961 | char *p, *cur; | ||
1962 | char *match = NULL; | ||
1963 | int goodness = 0; | ||
1964 | int result = 0; | ||
1965 | |||
1966 | extern char *sysmap; | ||
1967 | extern unsigned long sysmap_size; | ||
1968 | if ( !sysmap || !sysmap_size ) | ||
1969 | return 0; | ||
1970 | |||
1971 | if( setjmp(bus_error_jmp) == 0 ) { | ||
1972 | debugger_fault_handler = handle_fault; | ||
1973 | sync(); | ||
1974 | cur = sysmap; | ||
1975 | while(cur) { | ||
1976 | cur = strstr(cur, symbol); | ||
1977 | if (cur) { | ||
1978 | int gd = 1; | ||
1979 | |||
1980 | /* best match if equal, better match if | ||
1981 | * begins with | ||
1982 | */ | ||
1983 | if (cur == sysmap || *(cur-1) == ' ') { | ||
1984 | gd++; | ||
1985 | if (cur[strlen(symbol)] == 10) | ||
1986 | gd++; | ||
1987 | } | ||
1988 | if (gd > goodness) { | ||
1989 | match = cur; | ||
1990 | goodness = gd; | ||
1991 | if (gd == 3) | ||
1992 | break; | ||
1993 | } | ||
1994 | cur++; | ||
1995 | } | ||
1996 | } | ||
1997 | if (goodness) { | ||
1998 | p = match; | ||
1999 | while(p > sysmap && *p != 10) | ||
2000 | p--; | ||
2001 | if (*p == 10) p++; | ||
2002 | result = simple_strtoul(p, &p, 16); | ||
2003 | } | ||
2004 | sync(); | ||
2005 | } | ||
2006 | debugger_fault_handler = NULL; | ||
2007 | return result; | ||
2008 | } | ||