/* $OpenBSD: db_interface.c,v 1.26 2008/03/13 23:29:46 kettenis Exp $ */ /* $NetBSD: db_interface.c,v 1.61 2001/07/31 06:55:47 eeh Exp $ */ /* * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef notyet #include "fb.h" #include "esp_sbus.h" #endif #include "tda.h" db_regs_t ddb_regs; /* register state */ extern void OF_enter(void); extern struct traptrace { unsigned short tl:3, /* Trap level */ ns:4, /* PCB nsaved */ tt:9; /* Trap type */ unsigned short pid; /* PID */ u_int tstate; /* tstate */ u_int tsp; /* sp */ u_int tpc; /* pc */ u_int tfault; /* MMU tag access */ } trap_trace[], trap_trace_end[]; static long nil; static int db__char_value(struct db_variable *var, db_expr_t *expr, int mode) { switch (mode) { case DB_VAR_SET: *var->valuep = *(char *)expr; break; case DB_VAR_GET: *expr = *(char *)var->valuep; break; #ifdef DIAGNOSTIC default: printf("db__char_value: mode %d\n", mode); break; #endif } return 0; } #ifdef notdef_yet static int db__short_value(struct db_variable *var, db_expr_t *expr, int mode) { switch (mode) { case DB_VAR_SET: *var->valuep = *(short *)expr; break; case DB_VAR_GET: *expr = *(short *)var->valuep; break; #ifdef DIAGNOSTIC default: printf("db__short_value: mode %d\n", mode); break; #endif } return 0; } #endif struct db_variable db_regs[] = { { "tstate", (long *)&DDB_TF->tf_tstate, FCN_NULL, }, { "pc", (long *)&DDB_TF->tf_pc, FCN_NULL, }, { "npc", (long *)&DDB_TF->tf_npc, FCN_NULL, }, { "ipl", (long *)&DDB_TF->tf_oldpil, db__char_value, }, { "y", (long *)&DDB_TF->tf_y, db_var_rw_int, }, { "g0", (long *)&nil, FCN_NULL, }, { "g1", (long *)&DDB_TF->tf_global[1], FCN_NULL, }, { "g2", (long *)&DDB_TF->tf_global[2], FCN_NULL, }, { "g3", (long *)&DDB_TF->tf_global[3], FCN_NULL, }, { "g4", (long *)&DDB_TF->tf_global[4], FCN_NULL, }, { "g5", (long *)&DDB_TF->tf_global[5], FCN_NULL, }, { "g6", (long *)&DDB_TF->tf_global[6], FCN_NULL, }, { "g7", (long *)&DDB_TF->tf_global[7], FCN_NULL, }, { "o0", (long *)&DDB_TF->tf_out[0], FCN_NULL, }, { "o1", (long *)&DDB_TF->tf_out[1], FCN_NULL, }, { "o2", (long *)&DDB_TF->tf_out[2], FCN_NULL, }, { "o3", (long *)&DDB_TF->tf_out[3], FCN_NULL, }, { "o4", (long *)&DDB_TF->tf_out[4], FCN_NULL, }, { "o5", (long *)&DDB_TF->tf_out[5], FCN_NULL, }, { "o6", (long *)&DDB_TF->tf_out[6], FCN_NULL, }, { "o7", (long *)&DDB_TF->tf_out[7], FCN_NULL, }, { "l0", (long *)&DDB_TF->tf_local[0], FCN_NULL, }, { "l1", (long *)&DDB_TF->tf_local[1], FCN_NULL, }, { "l2", (long *)&DDB_TF->tf_local[2], FCN_NULL, }, { "l3", (long *)&DDB_TF->tf_local[3], FCN_NULL, }, { "l4", (long *)&DDB_TF->tf_local[4], FCN_NULL, }, { "l5", (long *)&DDB_TF->tf_local[5], FCN_NULL, }, { "l6", (long *)&DDB_TF->tf_local[6], FCN_NULL, }, { "l7", (long *)&DDB_TF->tf_local[7], FCN_NULL, }, { "i0", (long *)&DDB_FR->fr_arg[0], FCN_NULL, }, { "i1", (long *)&DDB_FR->fr_arg[1], FCN_NULL, }, { "i2", (long *)&DDB_FR->fr_arg[2], FCN_NULL, }, { "i3", (long *)&DDB_FR->fr_arg[3], FCN_NULL, }, { "i4", (long *)&DDB_FR->fr_arg[4], FCN_NULL, }, { "i5", (long *)&DDB_FR->fr_arg[5], FCN_NULL, }, { "i6", (long *)&DDB_FR->fr_arg[6], FCN_NULL, }, { "i7", (long *)&DDB_FR->fr_arg[7], FCN_NULL, }, { "f0", (long *)&DDB_FP->fs_regs[0], FCN_NULL, }, { "f2", (long *)&DDB_FP->fs_regs[2], FCN_NULL, }, { "f4", (long *)&DDB_FP->fs_regs[4], FCN_NULL, }, { "f6", (long *)&DDB_FP->fs_regs[6], FCN_NULL, }, { "f8", (long *)&DDB_FP->fs_regs[8], FCN_NULL, }, { "f10", (long *)&DDB_FP->fs_regs[10], FCN_NULL, }, { "f12", (long *)&DDB_FP->fs_regs[12], FCN_NULL, }, { "f14", (long *)&DDB_FP->fs_regs[14], FCN_NULL, }, { "f16", (long *)&DDB_FP->fs_regs[16], FCN_NULL, }, { "f18", (long *)&DDB_FP->fs_regs[18], FCN_NULL, }, { "f20", (long *)&DDB_FP->fs_regs[20], FCN_NULL, }, { "f22", (long *)&DDB_FP->fs_regs[22], FCN_NULL, }, { "f24", (long *)&DDB_FP->fs_regs[24], FCN_NULL, }, { "f26", (long *)&DDB_FP->fs_regs[26], FCN_NULL, }, { "f28", (long *)&DDB_FP->fs_regs[28], FCN_NULL, }, { "f30", (long *)&DDB_FP->fs_regs[30], FCN_NULL, }, { "f32", (long *)&DDB_FP->fs_regs[32], FCN_NULL, }, { "f34", (long *)&DDB_FP->fs_regs[34], FCN_NULL, }, { "f36", (long *)&DDB_FP->fs_regs[36], FCN_NULL, }, { "f38", (long *)&DDB_FP->fs_regs[38], FCN_NULL, }, { "f40", (long *)&DDB_FP->fs_regs[40], FCN_NULL, }, { "f42", (long *)&DDB_FP->fs_regs[42], FCN_NULL, }, { "f44", (long *)&DDB_FP->fs_regs[44], FCN_NULL, }, { "f46", (long *)&DDB_FP->fs_regs[46], FCN_NULL, }, { "f48", (long *)&DDB_FP->fs_regs[48], FCN_NULL, }, { "f50", (long *)&DDB_FP->fs_regs[50], FCN_NULL, }, { "f52", (long *)&DDB_FP->fs_regs[52], FCN_NULL, }, { "f54", (long *)&DDB_FP->fs_regs[54], FCN_NULL, }, { "f56", (long *)&DDB_FP->fs_regs[56], FCN_NULL, }, { "f58", (long *)&DDB_FP->fs_regs[58], FCN_NULL, }, { "f60", (long *)&DDB_FP->fs_regs[60], FCN_NULL, }, { "f62", (long *)&DDB_FP->fs_regs[62], FCN_NULL, }, { "fsr", (long *)&DDB_FP->fs_fsr, FCN_NULL, }, { "gsr", (long *)&DDB_FP->fs_gsr, FCN_NULL, }, }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); extern label_t *db_recover; int db_active = 0; extern char *trap_type[]; void kdb_kbd_trap(struct trapframe64 *); void db_prom_cmd(db_expr_t, int, db_expr_t, char *); void db_proc_cmd(db_expr_t, int, db_expr_t, char *); void db_ctx_cmd(db_expr_t, int, db_expr_t, char *); void db_dump_window(db_expr_t, int, db_expr_t, char *); void db_dump_stack(db_expr_t, int, db_expr_t, char *); void db_dump_trap(db_expr_t, int, db_expr_t, char *); void db_dump_fpstate(db_expr_t, int, db_expr_t, char *); void db_dump_ts(db_expr_t, int, db_expr_t, char *); void db_dump_pcb(db_expr_t, int, db_expr_t, char *); void db_dump_pv(db_expr_t, int, db_expr_t, char *); void db_setpcb(db_expr_t, int, db_expr_t, char *); void db_dump_dtlb(db_expr_t, int, db_expr_t, char *); void db_dump_itlb(db_expr_t, int, db_expr_t, char *); void db_dump_dtsb(db_expr_t, int, db_expr_t, char *); void db_pmap_kernel(db_expr_t, int, db_expr_t, char *); void db_pload_cmd(db_expr_t, int, db_expr_t, char *); void db_pmap_cmd(db_expr_t, int, db_expr_t, char *); void db_lock(db_expr_t, int, db_expr_t, char *); void db_traptrace(db_expr_t, int, db_expr_t, char *); void db_dump_buf(db_expr_t, int, db_expr_t, char *); void db_dump_espcmd(db_expr_t, int, db_expr_t, char *); void db_watch(db_expr_t, int, db_expr_t, char *); static void db_dump_pmap(struct pmap*); static void db_print_trace_entry(struct traptrace *, int); /* * Received keyboard interrupt sequence. */ void kdb_kbd_trap(tf) struct trapframe64 *tf; { if (db_active == 0 /* && (boothowto & RB_KDB) */) { printf("\n\nkernel: keyboard interrupt tf=%p\n", tf); kdb_trap(-1, tf); } } /* * kdb_trap - field a TRACE or BPT trap */ int kdb_trap(type, tf) int type; register struct trapframe64 *tf; { int s, tl; struct trapstate *ts = &ddb_regs.ddb_ts[0]; extern int savetstate(struct trapstate *ts); extern void restoretstate(int tl, struct trapstate *ts); extern int trap_trace_dis; trap_trace_dis++; #if NTDA > 0 tda_full_blast(); #endif fb_unblank(); switch (type) { case T_BREAKPOINT: /* breakpoint */ printf("kdb breakpoint at %llx\n", (unsigned long long)tf->tf_pc); break; case -1: /* keyboard interrupt */ printf("kdb tf=%p\n", tf); break; default: printf("kernel trap %x: %s\n", type, trap_type[type & 0x1ff]); if (db_recover != 0) { OF_enter(); db_error("Faulted in DDB; continuing...\n"); OF_enter(); /*NOTREACHED*/ } db_recover = (label_t *)1; } /* Should switch to kdb`s own stack here. */ write_all_windows(); ddb_regs.ddb_tf = *tf; if (fpproc) { savefpstate(fpproc->p_md.md_fpstate); ddb_regs.ddb_fpstate = *fpproc->p_md.md_fpstate; loadfpstate(fpproc->p_md.md_fpstate); } /* We should do a proper copyin and xlate 64-bit stack frames, but... */ /* if (tf->tf_tstate & TSTATE_PRIV) { */ #if 0 /* make sure this is not causing ddb problems. */ if (tf->tf_out[6] & 1) { if ((unsigned)(tf->tf_out[6] + BIAS) > (unsigned)KERNBASE) ddb_regs.ddb_fr = *(struct frame64 *)(tf->tf_out[6] + BIAS); else copyin((caddr_t)(tf->tf_out[6] + BIAS), &ddb_regs.ddb_fr, sizeof(struct frame64)); } else { struct frame32 tfr; /* First get a local copy of the frame32 */ if ((unsigned)(tf->tf_out[6]) > (unsigned)KERNBASE) tfr = *(struct frame32 *)tf->tf_out[6]; else copyin((caddr_t)(tf->tf_out[6]), &tfr, sizeof(struct frame32)); /* Now copy each field from the 32-bit value to the 64-bit value */ for (i=0; i<8; i++) ddb_regs.ddb_fr.fr_local[i] = tfr.fr_local[i]; for (i=0; i<6; i++) ddb_regs.ddb_fr.fr_arg[i] = tfr.fr_arg[i]; ddb_regs.ddb_fr.fr_fp = (long)tfr.fr_fp; ddb_regs.ddb_fr.fr_pc = tfr.fr_pc; } #endif s = splhigh(); db_active++; cnpollc(TRUE); /* Need to do spl stuff till cnpollc works */ tl = ddb_regs.ddb_tl = savetstate(ts); db_dump_ts(0, 0, 0, 0); db_trap(type, 0/*code*/); restoretstate(tl,ts); cnpollc(FALSE); db_active--; splx(s); if (fpproc) { *fpproc->p_md.md_fpstate = ddb_regs.ddb_fpstate; loadfpstate(fpproc->p_md.md_fpstate); } #if 0 /* We will not alter the machine's running state until we get everything else working */ *(struct frame *)tf->tf_out[6] = ddb_regs.ddb_fr; #endif *tf = ddb_regs.ddb_tf; trap_trace_dis--; return (1); } /* * Read bytes from kernel address space for debugger. */ void db_read_bytes(addr, size, data) vaddr_t addr; register size_t size; register char *data; { register char *src; src = (char *)addr; while (size-- > 0) { if (src >= (char *)VM_MIN_KERNEL_ADDRESS) *data++ = probeget((paddr_t)(u_long)src++, ASI_P, 1); else copyin(src++, data++, sizeof(u_char)); } } /* * Write bytes to kernel address space for debugger. */ void db_write_bytes(addr, size, data) vaddr_t addr; register size_t size; register char *data; { register char *dst; extern vaddr_t ktext; extern paddr_t ktextp; dst = (char *)addr; while (size-- > 0) { if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS+0x400000)) *dst = *data; else if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS) && (dst < (char *)VM_MIN_KERNEL_ADDRESS+0x400000)) /* Read Only mapping -- need to do a bypass access */ stba((u_long)dst - ktext + ktextp, ASI_PHYS_CACHED, *data); else copyout(data, dst, sizeof(char)); dst++, data++; } } void Debugger() { /* We use the breakpoint to trap into DDB */ asm("ta 1; nop"); } void db_prom_cmd(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { OF_enter(); } #define CHEETAHP (((getver()>>32) & 0x1ff) >= 0x14) unsigned long db_get_dtlb_data(int entry), db_get_dtlb_tag(int entry), db_get_itlb_data(int entry), db_get_itlb_tag(int entry); void db_print_itlb_entry(int entry, int i, int endc); void db_print_dtlb_entry(int entry, int i, int endc); extern __inline__ unsigned long db_get_dtlb_data(int entry) { unsigned long r; __asm__ __volatile__("ldxa [%1] %2,%0" : "=r" (r) : "r" (entry <<3), "i" (ASI_DMMU_TLB_DATA)); return r; } extern __inline__ unsigned long db_get_dtlb_tag(int entry) { unsigned long r; __asm__ __volatile__("ldxa [%1] %2,%0" : "=r" (r) : "r" (entry <<3), "i" (ASI_DMMU_TLB_TAG)); return r; } extern __inline__ unsigned long db_get_itlb_data(int entry) { unsigned long r; __asm__ __volatile__("ldxa [%1] %2,%0" : "=r" (r) : "r" (entry <<3), "i" (ASI_IMMU_TLB_DATA)); return r; } extern __inline__ unsigned long db_get_itlb_tag(int entry) { unsigned long r; __asm__ __volatile__("ldxa [%1] %2,%0" : "=r" (r) : "r" (entry <<3), "i" (ASI_IMMU_TLB_TAG)); return r; } void db_print_dtlb_entry(int entry, int i, int endc) { unsigned long tag, data; tag = db_get_dtlb_tag(entry); data = db_get_dtlb_data(entry); db_printf("%2d:%16.16lx %16.16lx%c", i, tag, data, endc); } void db_print_itlb_entry(int entry, int i, int endc) { unsigned long tag, data; tag = db_get_itlb_tag(entry); data = db_get_itlb_data(entry); db_printf("%2d:%16.16lx %16.16lx%c", i, tag, data, endc); } void db_dump_dtlb(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { /* extern void print_dtlb(void); -- locore.s; no longer used here */ if (have_addr) { int i; int64_t* p = (int64_t*)addr; static int64_t buf[128]; extern void dump_dtlb(int64_t *); if (CHEETAHP) { db_printf("DTLB %ld\n", addr); switch(addr) { case 0: for (i = 0; i < 16; ++i) db_print_dtlb_entry(i, i, (i&1)?'\n':' '); break; case 2: for (i = 0; i < 512; ++i) db_print_dtlb_entry(i+16384, i, (i&1)?'\n':' '); break; } } else { dump_dtlb(buf); p = buf; for (i=0; i<64;) { db_printf("%2d:%16.16llx %16.16llx ", i++, p[0], p[1]); p += 2; db_printf("%2d:%16.16llx %16.16llx\n", i++, p[0], p[1]); p += 2; } } } else { printf ("Usage: mach dtlb 0,2\n"); } } void db_dump_itlb(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { int i; if (!have_addr) { db_printf("Usage: mach itlb 0,1,2\n"); return; } if (CHEETAHP) { db_printf("ITLB %ld\n", addr); switch(addr) { case 0: for (i = 0; i < 16; ++i) db_print_itlb_entry(i, i, (i&1)?'\n':' '); break; case 2: for (i = 0; i < 128; ++i) db_print_itlb_entry(i+16384, i, (i&1)?'\n':' '); break; } } else { for (i = 0; i < 63; ++i) db_print_itlb_entry(i, i, (i&1)?'\n':' '); } } void db_pload_cmd(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { static paddr_t oldaddr = -1; int asi = ASI_PHYS_CACHED; if (!have_addr) { addr = oldaddr; } if (addr == -1) { db_printf("no address\n"); return; } addr &= ~0x7; /* align */ { register char c, *cp = modif; while ((c = *cp++) != 0) if (c == 'u') asi = ASI_AIUS; } while (count--) { if (db_print_position() == 0) { /* Always print the address. */ db_printf("%16.16lx:\t", addr); } oldaddr=addr; db_printf("%8.8lx\n", (long)ldxa(addr, asi)); addr += 8; if (db_print_position() != 0) db_end_line(0); } } int64_t pseg_get(struct pmap *, vaddr_t); void db_dump_pmap(pm) struct pmap* pm; { /* print all valid pages in the kernel pmap */ long i, j, k, n; paddr_t *pdir, *ptbl; /* Almost the same as pmap_collect() */ n = 0; for (i=0; ipm_segs[i], ASI_PHYS_CACHED))) { db_printf("pdir %ld at %lx:\n", i, (long)pdir); for (k=0; kpm_segs[%lx][%lx][%lx]=>%qx\n", (void *)addr, (u_long)va_to_seg(addr), (u_long)va_to_dir(addr), (u_long)va_to_pte(addr), (unsigned long long)data); } else { db_printf("No mapping for %p\n", (void *)addr); } return; } db_printf("pmap_kernel(%p) psegs %p phys %llx\n", &kernel_pmap_, kernel_pmap_.pm_segs, (unsigned long long)kernel_pmap_.pm_physaddr); if (full) { db_dump_pmap(&kernel_pmap_); } else { for (j=i=0; i %lx%c", i, seg, (j++%4)?'\t':'\n'); } } } void db_pmap_cmd(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { struct pmap* pm=NULL; int i, j=0, full = 0; { register char c, *cp = modif; if (modif) while ((c = *cp++) != 0) if (c == 'f') full = 1; } if (curproc && curproc->p_vmspace) pm = curproc->p_vmspace->vm_map.pmap; if (have_addr) { pm = (struct pmap*)addr; } db_printf("pmap %p: ctx %x refs %d physaddr %llx psegs %p\n", pm, pm->pm_ctx, pm->pm_refs, (unsigned long long)pm->pm_physaddr, pm->pm_segs); if (full) { db_dump_pmap(pm); } else { for (i=0; i %lx%c", i, seg, (j++%4)?'\t':'\n'); } } } void db_lock(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { #if 0 struct lock *l; if (!have_addr) { db_printf("What lock address?\n"); return; } l = (struct lock *)addr; db_printf("flags=%x\n waitcount=%x sharecount=%x " "exclusivecount=%x\n wmesg=%s recurselevel=%x\n", l->lk_flags, l->lk_waitcount, l->lk_sharecount, l->lk_exclusivecount, l->lk_wmesg, l->lk_recurselevel); #else db_printf("locks unsupported\n"); #endif } void db_dump_dtsb(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { extern pte_t *tsb_dmmu; extern int tsbsize; #define TSBENTS (512<>32), (int)tsb_dmmu[i].data); i++; db_printf("%4d:%4d:%08x %08x:%08x\n", i, (int)((tsb_dmmu[i].tag&TSB_TAG_G)?-1:TSB_TAG_CTX(tsb_dmmu[i].tag)), (int)((i<<13)|TSB_TAG_VA(tsb_dmmu[i].tag)), (int)(tsb_dmmu[i].data>>32), (int)tsb_dmmu[i].data); } } void db_page_cmd(db_expr_t, int, db_expr_t, char *); void db_page_cmd(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { if (!have_addr) { db_printf("Need paddr for page\n"); return; } db_printf("pa %llx pg %p\n", (unsigned long long)addr, PHYS_TO_VM_PAGE(addr)); } void db_proc_cmd(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { struct proc *p; p = curproc; if (have_addr) p = (struct proc*) addr; if (p == NULL) { db_printf("no current process\n"); return; } db_printf("process %p:", p); db_printf("pid:%d vmspace:%p pmap:%p ctx:%x wchan:%p pri:%d upri:%d\n", p->p_pid, p->p_vmspace, p->p_vmspace->vm_map.pmap, p->p_vmspace->vm_map.pmap->pm_ctx, p->p_wchan, p->p_priority, p->p_usrpri); db_printf("maxsaddr:%p ssiz:%dpg or %llxB\n", p->p_vmspace->vm_maxsaddr, p->p_vmspace->vm_ssize, (unsigned long long)ptoa(p->p_vmspace->vm_ssize)); db_printf("profile timer: %ld sec %ld usec\n", p->p_stats->p_timer[ITIMER_PROF].it_value.tv_sec, p->p_stats->p_timer[ITIMER_PROF].it_value.tv_usec); db_printf("pcb: %p tf: %p fpstate: %p\n", &p->p_addr->u_pcb, p->p_md.md_tf, p->p_md.md_fpstate); return; } void db_ctx_cmd(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { struct proc *p; /* XXX LOCKING XXX */ LIST_FOREACH(p, &allproc, p_list) { if (p->p_stat) { db_printf("process %p:", p); db_printf("pid:%d pmap:%p ctx:%x tf:%p fpstate %p " "lastcall:%s\n", p->p_pid, p->p_vmspace->vm_map.pmap, p->p_vmspace->vm_map.pmap->pm_ctx, p->p_md.md_tf, p->p_md.md_fpstate, (p->p_addr->u_pcb.lastcall)? p->p_addr->u_pcb.lastcall : "Null"); } } return; } void db_dump_pcb(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { struct pcb *pcb; int i; pcb = curpcb; if (have_addr) pcb = (struct pcb*) addr; db_printf("pcb@%p sp:%p pc:%p cwp:%d pil:%d nsaved:%x onfault:%p\nlastcall:%s\nfull windows:\n", pcb, (void *)(long)pcb->pcb_sp, (void *)(long)pcb->pcb_pc, pcb->pcb_cwp, pcb->pcb_pil, pcb->pcb_nsaved, (void *)pcb->pcb_onfault, (pcb->lastcall)?pcb->lastcall:"Null"); for (i=0; ipcb_nsaved; i++) { db_printf("win %d: at %llx local, in\n", i, (unsigned long long)pcb->pcb_rwsp[i]); db_printf("%16llx %16llx %16llx %16llx\n", (unsigned long long)pcb->pcb_rw[i].rw_local[0], (unsigned long long)pcb->pcb_rw[i].rw_local[1], (unsigned long long)pcb->pcb_rw[i].rw_local[2], (unsigned long long)pcb->pcb_rw[i].rw_local[3]); db_printf("%16llx %16llx %16llx %16llx\n", (unsigned long long)pcb->pcb_rw[i].rw_local[4], (unsigned long long)pcb->pcb_rw[i].rw_local[5], (unsigned long long)pcb->pcb_rw[i].rw_local[6], (unsigned long long)pcb->pcb_rw[i].rw_local[7]); db_printf("%16llx %16llx %16llx %16llx\n", (unsigned long long)pcb->pcb_rw[i].rw_in[0], (unsigned long long)pcb->pcb_rw[i].rw_in[1], (unsigned long long)pcb->pcb_rw[i].rw_in[2], (unsigned long long)pcb->pcb_rw[i].rw_in[3]); db_printf("%16llx %16llx %16llx %16llx\n", (unsigned long long)pcb->pcb_rw[i].rw_in[4], (unsigned long long)pcb->pcb_rw[i].rw_in[5], (unsigned long long)pcb->pcb_rw[i].rw_in[6], (unsigned long long)pcb->pcb_rw[i].rw_in[7]); } } void db_setpcb(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { struct proc *p, *pp; if (!have_addr) { db_printf("What PID do you want to map in?\n"); return; } LIST_FOREACH(p, &allproc, p_list) { pp = p->p_pptr; if (p->p_stat && p->p_pid == addr) { curproc = p; curpcb = (struct pcb*)p->p_addr; if (p->p_vmspace->vm_map.pmap->pm_ctx) { switchtoctx(p->p_vmspace->vm_map.pmap->pm_ctx); return; } db_printf("PID %ld has a null context.\n", addr); return; } } db_printf("PID %ld not found.\n", addr); } static void db_print_trace_entry(te, i) struct traptrace *te; int i; { db_printf("%d:%d p:%d tt:%d:%llx:%llx %llx:%llx ", i, (int)te->tl, (int)te->pid, (int)te->tt, (unsigned long long)te->tstate, (unsigned long long)te->tfault, (unsigned long long)te->tsp, (unsigned long long)te->tpc); db_printsym((u_long)te->tpc, DB_STGY_PROC, db_printf); db_printf(": "); if ((te->tpc && !(te->tpc&0x3)) && curproc && (curproc->p_pid == te->pid)) { db_disasm((u_long)te->tpc, 0); } else db_printf("\n"); } void db_traptrace(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { int i, start = 0, full = 0, reverse = 0; struct traptrace *end; start = 0; end = &trap_trace_end[0]; { register char c, *cp = modif; if (modif) while ((c = *cp++) != 0) { if (c == 'f') full = 1; if (c == 'r') reverse = 1; } } if (have_addr) { start = addr / (sizeof (struct traptrace)); if (&trap_trace[start] > &trap_trace_end[0]) { db_printf("Address out of range.\n"); return; } if (!full) end = &trap_trace[start+1]; } db_printf("#:tl p:pid tt:tt:tstate:tfault sp:pc\n"); if (reverse) { if (full && start) for (i=start; --i;) { db_print_trace_entry(&trap_trace[i], i); } i = (end - &trap_trace[0]); while(--i > start) { db_print_trace_entry(&trap_trace[i], i); } } else { for (i=start; &trap_trace[i] < end ; i++) { db_print_trace_entry(&trap_trace[i], i); } if (full && start) for (i=0; i < start ; i++) { db_print_trace_entry(&trap_trace[i], i); } } } /* * Use physical or virtual watchpoint registers -- ugh */ void db_watch(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { int phys = 0; #define WATCH_VR (1L<<22) #define WATCH_VW (1L<<21) #define WATCH_PR (1L<<24) #define WATCH_PW (1L<<23) #define WATCH_PM (((u_int64_t)0xffffL)<<33) #define WATCH_VM (((u_int64_t)0xffffL)<<25) { register char c, *cp = modif; if (modif) while ((c = *cp++) != 0) if (c == 'p') phys = 1; } if (have_addr) { /* turn on the watchpoint */ int64_t tmp = ldxa(0, ASI_MCCR); if (phys) { tmp &= ~(WATCH_PM|WATCH_PR|WATCH_PW); stxa(PHYSICAL_WATCHPOINT, ASI_DMMU, addr); } else { tmp &= ~(WATCH_VM|WATCH_VR|WATCH_VW); stxa(VIRTUAL_WATCHPOINT, ASI_DMMU, addr); } stxa(0, ASI_MCCR, tmp); } else { /* turn off the watchpoint */ int64_t tmp = ldxa(0, ASI_MCCR); if (phys) tmp &= ~(WATCH_PM); else tmp &= ~(WATCH_VM); stxa(0, ASI_MCCR, tmp); } } #include #ifdef UVMHIST void db_uvmhistdump(db_expr_t, int, db_expr_t, char *); extern void uvmhist_dump(struct uvm_history *); extern struct uvm_history_head uvm_histories; void db_uvmhistdump(addr, have_addr, count, modif) db_expr_t addr; int have_addr; db_expr_t count; char *modif; { uvmhist_dump(LIST_FIRST(&uvm_histories)); } #endif #if NESP_SBUS extern void db_esp(db_expr_t, int, db_expr_t, char *); #endif struct db_command db_machine_command_table[] = { { "ctx", db_ctx_cmd, 0, 0 }, { "dtlb", db_dump_dtlb, 0, 0 }, { "dtsb", db_dump_dtsb, 0, 0 }, #if NESP_SBUS { "esp", db_esp, 0, 0 }, #endif { "fpstate", db_dump_fpstate,0, 0 }, { "itlb", db_dump_itlb, 0, 0 }, { "kmap", db_pmap_kernel, 0, 0 }, { "lock", db_lock, 0, 0 }, { "pcb", db_dump_pcb, 0, 0 }, { "pctx", db_setpcb, 0, 0 }, { "page", db_page_cmd, 0, 0 }, { "phys", db_pload_cmd, 0, 0 }, { "pmap", db_pmap_cmd, 0, 0 }, { "proc", db_proc_cmd, 0, 0 }, { "prom", db_prom_cmd, 0, 0 }, { "pv", db_dump_pv, 0, 0 }, { "stack", db_dump_stack, 0, 0 }, { "tf", db_dump_trap, 0, 0 }, { "ts", db_dump_ts, 0, 0 }, { "traptrace", db_traptrace, 0, 0 }, #ifdef UVMHIST { "uvmdump", db_uvmhistdump, 0, 0 }, #endif { "watch", db_watch, 0, 0 }, { "window", db_dump_window, 0, 0 }, { (char *)0, } }; /* * support for SOFTWARE_SSTEP: * return the next pc if the given branch is taken. * * note: in the case of conditional branches with annul, * this actually returns the next pc in the "not taken" path, * but in that case next_instr_address() will return the * next pc in the "taken" path. so even tho the breakpoints * are backwards, everything will still work, and the logic is * much simpler this way. */ db_addr_t db_branch_taken(inst, pc, regs) int inst; db_addr_t pc; db_regs_t *regs; { union instr insn; db_addr_t npc = ddb_regs.ddb_tf.tf_npc; insn.i_int = inst; /* the fancy union just gets in the way of this: */ switch(inst & 0xffc00000) { case 0x30400000: /* branch always, annul, with prediction */ return pc + ((inst<<(32-19))>>((32-19)-2)); case 0x30800000: /* branch always, annul */ return pc + ((inst<<(32-22))>>((32-22)-2)); } /* * if this is not an annulled conditional branch, the next pc is "npc". */ if (insn.i_any.i_op != IOP_OP2 || insn.i_branch.i_annul != 1) return npc; switch (insn.i_op2.i_op2) { case IOP2_Bicc: case IOP2_FBfcc: case IOP2_BPcc: case IOP2_FBPfcc: case IOP2_CBccc: /* branch on some condition-code */ switch (insn.i_branch.i_cond) { case Icc_A: /* always */ return pc + ((inst << 10) >> 8); default: /* all other conditions */ return npc + 4; } case IOP2_BPr: /* branch on register, always conditional */ return npc + 4; default: /* not a branch */ panic("branch_taken() on non-branch"); } } boolean_t db_inst_branch(inst) int inst; { union instr insn; insn.i_int = inst; /* the fancy union just gets in the way of this: */ switch(inst & 0xffc00000) { case 0x30400000: /* branch always, annul, with prediction */ return TRUE; case 0x30800000: /* branch always, annul */ return TRUE; } if (insn.i_any.i_op != IOP_OP2) return FALSE; switch (insn.i_op2.i_op2) { case IOP2_BPcc: case IOP2_Bicc: case IOP2_BPr: case IOP2_FBPfcc: case IOP2_FBfcc: case IOP2_CBccc: return TRUE; default: return FALSE; } } boolean_t db_inst_call(inst) int inst; { union instr insn; insn.i_int = inst; switch (insn.i_any.i_op) { case IOP_CALL: return TRUE; case IOP_reg: return (insn.i_op3.i_op3 == IOP3_JMPL) && !db_inst_return(inst); default: return FALSE; } } boolean_t db_inst_unconditional_flow_transfer(inst) int inst; { union instr insn; insn.i_int = inst; if (db_inst_call(inst)) return TRUE; if (insn.i_any.i_op != IOP_OP2) return FALSE; switch (insn.i_op2.i_op2) { case IOP2_BPcc: case IOP2_Bicc: case IOP2_FBPfcc: case IOP2_FBfcc: case IOP2_CBccc: return insn.i_branch.i_cond == Icc_A; default: return FALSE; } } boolean_t db_inst_return(inst) int inst; { return (inst == I_JMPLri(I_G0, I_O7, 8) || /* ret */ inst == I_JMPLri(I_G0, I_I7, 8)); /* retl */ } boolean_t db_inst_trap_return(inst) int inst; { union instr insn; insn.i_int = inst; return (insn.i_any.i_op == IOP_reg && insn.i_op3.i_op3 == IOP3_RETT); } int db_inst_load(inst) int inst; { union instr insn; insn.i_int = inst; if (insn.i_any.i_op != IOP_mem) return 0; switch (insn.i_op3.i_op3) { case IOP3_LD: case IOP3_LDUB: case IOP3_LDUH: case IOP3_LDD: case IOP3_LDSB: case IOP3_LDSH: case IOP3_LDSTUB: case IOP3_SWAP: case IOP3_LDA: case IOP3_LDUBA: case IOP3_LDUHA: case IOP3_LDDA: case IOP3_LDSBA: case IOP3_LDSHA: case IOP3_LDSTUBA: case IOP3_SWAPA: case IOP3_LDF: case IOP3_LDFSR: case IOP3_LDDF: case IOP3_LFC: case IOP3_LDCSR: case IOP3_LDDC: return 1; default: return 0; } } int db_inst_store(inst) int inst; { union instr insn; insn.i_int = inst; if (insn.i_any.i_op != IOP_mem) return 0; switch (insn.i_op3.i_op3) { case IOP3_ST: case IOP3_STB: case IOP3_STH: case IOP3_STD: case IOP3_LDSTUB: case IOP3_SWAP: case IOP3_STA: case IOP3_STBA: case IOP3_STHA: case IOP3_STDA: case IOP3_LDSTUBA: case IOP3_SWAPA: case IOP3_STF: case IOP3_STFSR: case IOP3_STQF: case IOP3_STDF: case IOP3_STC: case IOP3_STCSR: case IOP3_STQFA: case IOP3_STDC: return 1; default: return 0; } } void db_machine_init() { db_machine_commands_install(db_machine_command_table); }