--- linux-2.6.11.5.orig/arch/ppc64/xmon/xmon.c 2005-04-05 16:53:28.180666276 -0500 +++ linux-2.6.11.5/arch/ppc64/xmon/xmon.c 2005-04-06 09:24:07.844169471 -0500 @@ -56,6 +56,7 @@ static unsigned long ncsum = 4096; static int termch; static char tmpstr[128]; +static unsigned long xmon_active_pid=0; #define JMP_BUF_LEN (184/sizeof(long)) static long bus_error_jmp[JMP_BUF_LEN]; @@ -129,6 +130,12 @@ static int cpu_cmd(void); static void csum(void); static void bootcmds(void); +static void willcmds(void); +static void xmon_dump_all_pids(void); +static void xmon_get_pid(void); +static void xmon_decode_slb(void); +static void xmon_dump_proc_gprs(void); +static void xmon_dump_proc_memory_address(void); void dump_segments(void); static void symbol_lookup(void); static void xmon_print_symbol(unsigned long address, const char *mid, @@ -860,6 +867,9 @@ case 'u': dump_segments(); break; + case 'w': + willcmds(); + break; default: printf("Unrecognized command: "); do { @@ -2485,6 +2495,278 @@ } } +/* + * based on find_linux_pte. This func requires pgd and ea, and will return pte + */ +static inline pte_t *xmon_find_linux_pte(pgd_t *pgdir, unsigned long ea) +{ + pgd_t *pgd; + pmd_t *pm; + pte_t *pt = NULL; + pte_t pte; + + if (setjmp(bus_error_jmp) == 0) { + catch_memory_errors = 1; + sync(); + + /* pgd = pgd_offset(mm,ea); */ + pgd = pgdir + pgd_index(ea); + + printf(" Page Info: pgd(0x%lx) ",pgd); + + if (!pgd_none(*pgd)) { + pm = pmd_offset(pgd, ea); + if (pmd_present(*pm)) { + pt = pte_offset_kernel(pm, ea); + pte = *pt; + printf("pm: 0x%lx ",pm); + printf("pte: 0x%lx ",pte); + printf("pt: 0x%lx \n",pt); + if (!pte_present(pte)) { + printf("!! pte not present;\n"); + pt = NULL; + } + } else + printf("!! pmd not present \n"); + } else + printf("!! no pgd \n"); + } + /* wait a little while to see if we get a machine check */ + __delay(200); + catch_memory_errors = 0; + return pt; +} + +/* + * takes a pid as input, this will return a pointer to the task_struct. + * This also displays some task info. (task->comm; task and pt_regs addresses). + */ +static inline struct task_struct * xmon_find_task_addr(unsigned long mypid) +{ + struct task_struct *task_addr=NULL; + + if (setjmp(bus_error_jmp) == 0) { + catch_memory_errors = 1; + sync(); + + /* normally, calls to find_task_by_pid are protected by tasklist_lock. */ + task_addr=find_task_by_pid(mypid); + + if (task_addr) { + if (task_addr->comm) + printf("[%-16.16s] ",task_addr->comm); + printf("pid:(%-6.6x) task:(%lx) ",mypid,task_addr); + printf("thread:(%lx) ",task_addr->thread); + if (task_addr->thread.regs) + printf(" pt_regs:(%lx)\n",task_addr->thread.regs); + else + printf("\n"); + } else { + /* printf("NULL task_addr\n"); -- this one is noisy */ + } + } + /* wait a little while to see if we get a machine check */ + __delay(200); + catch_memory_errors = 0; + return task_addr; +} + +/* + * given a ptep, this will return a kernel-addressible address + */ +static inline unsigned long xmon_find_real_addr(pte_t* ptep) +{ + unsigned long real_addr=0; + pte_t pte; + struct page * page; + + if (setjmp(bus_error_jmp) == 0) { + catch_memory_errors = 1; + sync(); + + if (ptep) { + pte = *ptep; + page = (struct page *) pte_page(pte); + real_addr = (unsigned long) page_address(page); + } + } + /* wait a little while to see if we get a machine check */ + __delay(200); + catch_memory_errors = 0; + return real_addr; +} + +/* + * given task_struct and Effective Address, this will return a pgd. + */ +static inline pgd_t *xmon_find_pgd (struct task_struct *task_addr,unsigned long ea) +{ + pgd_t *pgd; + struct mm_struct *mm; + + pgd=NULL; + + if (setjmp(bus_error_jmp) == 0) { + catch_memory_errors = 1; + sync(); + + if (task_addr) { + mm = task_addr->mm; + if (mm) { + pgd=pgd_offset(mm,ea); + } else { + printf("!! no mm \n"); + } + } else { + printf("!! no task_addr \n"); + } + } + /* wait a little while to see if we get a machine check */ + __delay(200); + catch_memory_errors = 0; + return pgd; +} + +static char *wms_help_string = "\ +Commands:\n\ + wd retrieve xmon-addressable address\n\ + wg dump gprs for 'selected' process\n\ + wh Show this help\n\ + wp 'select' a process\n\ + wP show all processes\n\ + ws dump decoded SLB\n\ + w? Show this help\n" +; + +static void willcmds(void) +{ + int cmd; + + cmd = inchar(); + switch (cmd) { + case '?': + case 'h': + printf(wms_help_string); + break; + case 'P': + xmon_dump_all_pids(); + break; + case 'p': + xmon_get_pid(); + break; + case 'g': + xmon_dump_proc_gprs(); + break; + case 'd': + xmon_dump_proc_memory_address(); + break; + case 's': + xmon_decode_slb(); + break; + default: + printf("hi!\n"); + } +} + +/* display thread.regs for 'selected' process */ +static void xmon_dump_proc_gprs(void) +{ + unsigned long mypid; + struct task_struct *task_addr; + + mypid = xmon_active_pid; + + task_addr = xmon_find_task_addr(mypid); + + if (!task_addr) return; + + prregs(task_addr->thread.regs); +} + +static void xmon_dump_proc_memory_address(void) +{ + struct task_struct *task_addr; + unsigned long mypid; + unsigned long target_addr; + unsigned long real_addr; + pgd_t *pgd; + pte_t *ptep; + + scanhex((void *)&target_addr); + + mypid = xmon_active_pid; + if (!mypid) return; + + task_addr = xmon_find_task_addr(mypid); + + pgd = xmon_find_pgd(task_addr,target_addr); + + ptep = xmon_find_linux_pte(pgd,target_addr); + + real_addr = xmon_find_real_addr(ptep); + + printf("target_addr: 0x%p ",target_addr); + printf("target_pid: 0x%p ",mypid); + printf("real_address: 0x%p \n",real_addr); + + return; +} + + +static void xmon_decode_slb(void) +{ + int i; + unsigned long tmp1; + unsigned long tmp2; + unsigned long valid; + + printf("SLB contents of cpu %x\n===",smp_processor_id()); + + for (i=0; i < SLB_NUM_ENTRIES; i++) { + asm volatile("slbmfee %0,%1" : "=r" (tmp1) : "r" (i)); + asm volatile("slbmfev %0,%1" : "=r" (tmp2) : "r" (i)); + valid = (1 < (tmp1 & 0x8000000)); + printf("\n%02d %016lx ", i, tmp1); + printf("%016lx",tmp2); + if (valid) { + printf(" ESID=%lx VSID=%lx ", GET_ESID(tmp1) ,(tmp2 & 0xfffffffffffff000)>>12); + } else { + /* printf(" . "); */ + } + } + printf("\n"); +} + +/* read pid value from stdin and set the active_pid variable */ +static void xmon_get_pid(void) +{ + struct task_struct *task_addr; + unsigned long mypid; + + scanhex((void *)&mypid); + + if (mypid) { + /* call xmon_find_task_addr to verify the pid is valid */ + task_addr = xmon_find_task_addr(mypid); + if (task_addr) + xmon_active_pid = mypid; + else + printf("Invalid Pid! \n"); + } else + printf("Invalid Pid! \n"); +} + +/* cycle through all possible pids, and subsequently display some basic task info for each */ +static void xmon_dump_all_pids(void) +{ + int mypid; + struct task_struct *task_addr; + + for (mypid=0;mypid