📄 xmon.c
字号:
/* * Routines providing a simple monitor for use on the PowerMac. * * Copyright (C) 1996 Paul Mackerras. */#include <linux/config.h>#include <linux/errno.h>#include <linux/sched.h>#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"#define scanhex xmon_scanhex#define skipbl xmon_skipbl#ifdef CONFIG_SMPstatic unsigned long cpus_in_xmon = 0;static unsigned long got_xmon = 0;static volatile int take_xmon = -1;#endif /* CONFIG_SMP */static unsigned adrs;static int size = 1;static unsigned ndump = 64;static unsigned nidump = 16;static unsigned ncsum = 4096;static int termch;static u_int bus_error_jmp[100];#define setjmp xmon_setjmp#define longjmp xmon_longjmp/* Breakpoint stuff */struct bpt { unsigned address; unsigned instr; unsigned count; unsigned char enabled;};#define NBPTS 16static struct bpt bpts[NBPTS];static struct bpt dabr;static struct bpt iabr;static unsigned bpinstr = 0x7fe00008; /* trap *//* Prototypes */extern void (*debugger_fault_handler)(struct pt_regs *);static int cmds(struct pt_regs *);static int mread(unsigned, void *, int);static int mwrite(unsigned, void *, int);static void handle_fault(struct pt_regs *);static void byterev(unsigned char *, int);static void memex(void);static int bsesc(void);static void dump(void);static void prdump(unsigned, int);#ifdef __MWERKS__static void prndump(unsigned, int);static int nvreadb(unsigned);#endifstatic int ppc_inst_dump(unsigned, int);void print_address(unsigned);static int getsp(void);static void dump_hash_table(void);static void backtrace(struct pt_regs *);static void excprint(struct pt_regs *);static void prregs(struct pt_regs *);static void memops(int);static void memlocate(void);static void memzcan(void);static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned);int skipbl(void);int scanhex(unsigned *valp);static void scannl(void);static int hexdigit(int);void getstring(char *, int);static void flush_input(void);static int inchar(void);static void take_input(char *);/* static void openforth(void); */static unsigned read_spr(int);static void write_spr(int, unsigned);static void super_regs(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);#ifdef CONFIG_SMPstatic void cpu_cmd(void);#endif /* CONFIG_SMP */static void csum(void);#ifdef CONFIG_BOOTX_TEXTstatic void vidcmds(void);#endifstatic void bootcmds(void);static void proccall(void);static void printtime(void);extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);extern void printf(const char *fmt, ...);extern int putchar(int ch);extern int setjmp(u_int *);extern void longjmp(u_int *, int);extern void xmon_enter(void);extern void xmon_leave(void);static unsigned start_tb[NR_CPUS][2];static unsigned stop_tb[NR_CPUS][2];#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ || ('a' <= (c) && (c) <= 'f') \ || ('A' <= (c) && (c) <= 'F'))#define isalnum(c) (('0' <= (c) && (c) <= '9') \ || ('a' <= (c) && (c) <= 'z') \ || ('A' <= (c) && (c) <= 'Z'))#define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)static char *help_string = "\Commands:\n\ d dump bytes\n\ di dump instructions\n\ df dump float values\n\ dd dump double values\n\ e print exception information\n\ h dump hash table\n\ m examine/change memory\n\ mm move a block of memory\n\ ms set a block of memory\n\ md compare two blocks of memory\n\ r print registers\n\ S print special registers\n\ t print backtrace\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];#define SSTEP 1 /* stepping because of 's' command */#define BRSTEP 2 /* stepping over breakpoint */static struct pt_regs *xmon_regs[NR_CPUS];extern inline void sync(void){ asm volatile("sync; isync");}extern inline void __delay(unsigned int loops){ if (loops != 0) __asm__ __volatile__("mtctr %0; 1: bdnz 1b" : : "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; if ((get_pvr() >> 16) == 1) return; do { asm volatile("mftbu %0; mftb %1; mftbu %2" : "=r" (hi), "=r" (lo), "=r" (hiagain)); } while (hi != hiagain); p[0] = hi; p[1] = lo;}int xmon(struct pt_regs *excp){ struct pt_regs regs; int msr, cmd; get_tb(stop_tb[smp_processor_id()]); if (excp == NULL) { asm volatile ("stw 0,0(%0)\n\ lwz 0,0(1)\n\ stw 0,4(%0)\n\ stmw 2,8(%0)" : : "b" (®s)); regs.nip = regs.link = ((unsigned long *)regs.gpr[1])[1]; regs.msr = get_msr(); regs.ctr = get_ctr(); regs.xer = get_xer(); regs.ccr = get_cr(); regs.trap = 0; excp = ®s; } msr = get_msr(); set_msr(msr & ~0x8000); /* disable interrupts */ xmon_regs[smp_processor_id()] = excp; xmon_enter(); excprint(excp);#ifdef CONFIG_SMP if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon)) for (;;) ; while (test_and_set_bit(0, &got_xmon)) { if (take_xmon == smp_processor_id()) { take_xmon = -1; break; } } /* * XXX: breakpoints are removed while any cpu is in xmon */#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; excp->msr |= 0x400; } else if (at_breakpoint(excp->nip)) { xmon_trace[smp_processor_id()] = BRSTEP; excp->msr |= 0x400; } else { xmon_trace[smp_processor_id()] = 0; insert_bpts(); } xmon_leave(); xmon_regs[smp_processor_id()] = NULL;#ifdef CONFIG_SMP clear_bit(0, &got_xmon); clear_bit(smp_processor_id(), &cpus_in_xmon);#endif /* CONFIG_SMP */ set_msr(msr); /* restore interrupt enable */ get_tb(start_tb[smp_processor_id()]); return cmd != 'X';}irqreturn_txmon_irq(int irq, void *d, struct pt_regs *regs){ unsigned long flags; local_irq_save(flags); printf("Keyboard interrupt\n"); xmon(regs); local_irq_restore(flags); return IRQ_HANDLED;}intxmon_bpt(struct pt_regs *regs){ struct bpt *bp; bp = at_breakpoint(regs->nip); if (!bp) return 0; if (bp->count) { --bp->count; remove_bpts(); excprint(regs); xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { xmon(regs); } return 1;}intxmon_sstep(struct pt_regs *regs){ if (!xmon_trace[smp_processor_id()]) return 0; if (xmon_trace[smp_processor_id()] == BRSTEP) { xmon_trace[smp_processor_id()] = 0; insert_bpts(); } else { xmon(regs); } return 1;}intxmon_dabr_match(struct pt_regs *regs){ if (dabr.enabled && dabr.count) { --dabr.count; remove_bpts(); excprint(regs); xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { dabr.instr = regs->nip; xmon(regs); } return 1;}intxmon_iabr_match(struct pt_regs *regs){ if (iabr.enabled && iabr.count) { --iabr.count; remove_bpts(); excprint(regs); xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { xmon(regs); } return 1;}static struct bpt *at_breakpoint(unsigned pc){ int i; struct bpt *bp; if (dabr.enabled && pc == dabr.instr) return &dabr; if (iabr.enabled && pc == iabr.address) return &iabr; bp = bpts; for (i = 0; i < NBPTS; ++i, ++bp) if (bp->enabled && pc == bp->address) return bp; return NULL;}static voidinsert_bpts(void){ int i; struct bpt *bp; bp = bpts; for (i = 0; i < NBPTS; ++i, ++bp) { if (!bp->enabled) continue; if (mread(bp->address, &bp->instr, 4) != 4 || mwrite(bp->address, &bpinstr, 4) != 4) { printf("Couldn't insert breakpoint at %x, disabling\n", bp->address); bp->enabled = 0; } store_inst((void *) bp->address); }#if !defined(CONFIG_8xx) if (dabr.enabled) set_dabr(dabr.address); if (iabr.enabled) set_iabr(iabr.address);#endif}static voidremove_bpts(void){ int i; struct bpt *bp; unsigned instr;#if !defined(CONFIG_8xx) set_dabr(0); set_iabr(0);#endif bp = bpts; for (i = 0; i < NBPTS; ++i, ++bp) { if (!bp->enabled) continue; if (mread(bp->address, &instr, 4) == 4 && instr == bpinstr && mwrite(bp->address, &bp->instr, 4) != 4) printf("Couldn't remove breakpoint at %x\n", bp->address); store_inst((void *) bp->address); }}static char *last_cmd;/* Command interpreting routine */static intcmds(struct pt_regs *excp){ int cmd; last_cmd = NULL; for(;;) {#ifdef CONFIG_SMP printf("%d:", smp_processor_id());#endif /* CONFIG_SMP */ printf("mon> "); fflush(stdout); flush_input(); termch = 0; cmd = skipbl(); if( cmd == '\n' ) { if (last_cmd == NULL) continue; take_input(last_cmd); last_cmd = NULL; cmd = inchar(); } switch (cmd) { case 'm': cmd = inchar(); switch (cmd) { case 'm': case 's': case 'd': memops(cmd); break; case 'l': memlocate(); break; case 'z': memzcan(); break; default: termch = cmd; memex(); } break; case 'd': dump(); break; case 'l': symbol_lookup(); break; case 'r': if (excp != NULL) prregs(excp); /* print regs */ break; case 'e': if (excp == NULL) printf("No exception information\n"); else excprint(excp); break; case 'S': super_regs(); break; case 't': backtrace(excp); break; case 'f': cacheflush(); break; case 'h': dump_hash_table(); break; case 's': case 'x': case EOF: return cmd; case '?': printf(help_string); break; default: printf("Unrecognized command: "); if( ' ' < cmd && cmd <= '~' ) putchar(cmd); else printf("\\x%x", cmd); printf(" (type ? for help)\n"); break; case 'b': bpt_cmds(); break; case 'C': csum(); break;#ifdef CONFIG_SMP case 'c': cpu_cmd(); break;#endif /* CONFIG_SMP */#ifdef CONFIG_BOOTX_TEXT case 'v': vidcmds(); break;#endif case 'z': bootcmds(); break; case 'p': proccall(); break; case 'T': printtime(); break; } }}extern unsigned tb_to_us;#define mulhwu(x,y) \({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})static void printtime(void){ unsigned int delta; delta = stop_tb[smp_processor_id()][1] - start_tb[smp_processor_id()][1]; delta = mulhwu(tb_to_us, delta); printf("%u.%06u seconds\n", delta / 1000000, delta % 1000000);}static void bootcmds(void){ int cmd; cmd = inchar(); if (cmd == 'r') ppc_md.restart(NULL); else if (cmd == 'h') ppc_md.halt(); else if (cmd == 'p') ppc_md.power_off();}#ifdef CONFIG_SMPstatic void cpu_cmd(void){ unsigned cpu; int timeout; int cmd; cmd = inchar(); if (cmd == 'i') { /* interrupt other cpu(s) */ cpu = MSG_ALL_BUT_SELF; if (scanhex(&cpu)) smp_send_xmon_break(cpu); return; } termch = cmd; if (!scanhex(&cpu)) { /* print cpus waiting or in xmon */ printf("cpus stopped:"); for (cpu = 0; cpu < NR_CPUS; ++cpu) { if (test_bit(cpu, &cpus_in_xmon)) { printf(" %d", cpu); if (cpu == smp_processor_id()) printf("*", cpu); } } printf("\n"); return; } /* try to switch to cpu specified */ take_xmon = cpu; timeout = 10000000; while (take_xmon >= 0) { if (--timeout == 0) { /* yes there's a race here */ take_xmon = -1; printf("cpu %u didn't take control\n", cpu); return; } } /* now have to wait to be given control back */ while (test_and_set_bit(0, &got_xmon)) { if (take_xmon == smp_processor_id()) { take_xmon = -1; break; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -