diff --git a/sys/alpha/alpha/db_interface.c b/sys/alpha/alpha/db_interface.c index 1e015aecce75..bb3fbf8a336c 100644 --- a/sys/alpha/alpha/db_interface.c +++ b/sys/alpha/alpha/db_interface.c @@ -1,548 +1,696 @@ /* $NetBSD: db_interface.c,v 1.2 1997/09/16 19:07:19 thorpej Exp $ */ /* $FreeBSD$ */ /* * Mach Operating System * Copyright (c) 1992,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 * 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. * * db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) */ /* * Parts of this file are derived from Mach 3: * * File: alpha_instruction.c * Author: Alessandro Forin, Carnegie Mellon University * Date: 6/92 */ /* * Interface to DDB. * * Modified for NetBSD/alpha by: * * Christopher G. Demetriou, Carnegie Mellon University * * Jason R. Thorpe, Numerical Aerospace Simulation Facility, * NASA Ames Research Center */ #include /* RCS ID & Copyright macro defns */ /* __KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.2 1997/09/16 19:07:19 thorpej Exp $"); */ #include #include #include #include #include #include +#include #include #include #include #include +#include +#include #include #include #include #include #include #include static jmp_buf *db_nofault = 0; extern jmp_buf db_jmpbuf; extern void gdb_handle_exception __P((db_regs_t *, int, int)); #if 0 extern char *trap_type[]; extern int trap_types; #endif int db_active; void ddbprinttrap __P((unsigned long, unsigned long, unsigned long, unsigned long)); struct db_variable db_regs[] = { { "v0", &ddb_regs.tf_regs[FRAME_V0], FCN_NULL }, { "t0", &ddb_regs.tf_regs[FRAME_T0], FCN_NULL }, { "t1", &ddb_regs.tf_regs[FRAME_T1], FCN_NULL }, { "t2", &ddb_regs.tf_regs[FRAME_T2], FCN_NULL }, { "t3", &ddb_regs.tf_regs[FRAME_T3], FCN_NULL }, { "t4", &ddb_regs.tf_regs[FRAME_T4], FCN_NULL }, { "t5", &ddb_regs.tf_regs[FRAME_T5], FCN_NULL }, { "t6", &ddb_regs.tf_regs[FRAME_T6], FCN_NULL }, { "t7", &ddb_regs.tf_regs[FRAME_T7], FCN_NULL }, { "s0", &ddb_regs.tf_regs[FRAME_S0], FCN_NULL }, { "s1", &ddb_regs.tf_regs[FRAME_S1], FCN_NULL }, { "s2", &ddb_regs.tf_regs[FRAME_S2], FCN_NULL }, { "s3", &ddb_regs.tf_regs[FRAME_S3], FCN_NULL }, { "s4", &ddb_regs.tf_regs[FRAME_S4], FCN_NULL }, { "s5", &ddb_regs.tf_regs[FRAME_S5], FCN_NULL }, { "s6", &ddb_regs.tf_regs[FRAME_S6], FCN_NULL }, { "a0", &ddb_regs.tf_regs[FRAME_A0], FCN_NULL }, { "a1", &ddb_regs.tf_regs[FRAME_A1], FCN_NULL }, { "a2", &ddb_regs.tf_regs[FRAME_A2], FCN_NULL }, { "a3", &ddb_regs.tf_regs[FRAME_A3], FCN_NULL }, { "a4", &ddb_regs.tf_regs[FRAME_A4], FCN_NULL }, { "a5", &ddb_regs.tf_regs[FRAME_A5], FCN_NULL }, { "t8", &ddb_regs.tf_regs[FRAME_T8], FCN_NULL }, { "t9", &ddb_regs.tf_regs[FRAME_T9], FCN_NULL }, { "t10", &ddb_regs.tf_regs[FRAME_T10], FCN_NULL }, { "t11", &ddb_regs.tf_regs[FRAME_T11], FCN_NULL }, { "ra", &ddb_regs.tf_regs[FRAME_RA], FCN_NULL }, { "t12", &ddb_regs.tf_regs[FRAME_T12], FCN_NULL }, { "at", &ddb_regs.tf_regs[FRAME_AT], FCN_NULL }, { "gp", &ddb_regs.tf_regs[FRAME_GP], FCN_NULL }, { "sp", &ddb_regs.tf_regs[FRAME_SP], FCN_NULL }, { "pc", &ddb_regs.tf_regs[FRAME_PC], FCN_NULL }, { "ps", &ddb_regs.tf_regs[FRAME_PS], FCN_NULL }, { "ai", &ddb_regs.tf_regs[FRAME_T11], FCN_NULL }, { "pv", &ddb_regs.tf_regs[FRAME_T12], FCN_NULL }, }; struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]); /* * Print trap reason. */ void ddbprinttrap(a0, a1, a2, entry) unsigned long a0, a1, a2, entry; { /* XXX Implement. */ printf("ddbprinttrap(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", a0, a1, a2, entry); } /* * ddb_trap - field a kernel trap */ int kdb_trap(a0, a1, a2, entry, regs) unsigned long a0, a1, a2, entry; db_regs_t *regs; { int ddb_mode = !(boothowto & RB_GDB); int s; /* * Don't bother checking for usermode, since a benign entry * by the kernel (call to Debugger() or a breakpoint) has * already checked for usermode. If neither of those * conditions exist, something Bad has happened. */ if (entry != ALPHA_KENTRY_IF || (a0 != ALPHA_IF_CODE_BUGCHK && a0 != ALPHA_IF_CODE_BPT && a0 != ALPHA_IF_CODE_GENTRAP)) { +#if 0 if (ddb_mode) { db_printf("ddbprinttrap from 0x%lx\n", /* XXX */ regs->tf_regs[FRAME_PC]); ddbprinttrap(a0, a1, a2, entry); /* * Tell caller "We did NOT handle the trap." * Caller should panic, or whatever. */ return (0); } +#endif if (db_nofault) { jmp_buf *no_fault = db_nofault; db_nofault = 0; + mtx_exit(&Giant, MTX_DEF); longjmp(*no_fault, 1); } } /* * XXX Should switch to DDB's own stack, here. */ ddb_regs = *regs; s = splhigh(); +#if 0 + db_printf("stopping %x\n", PCPU_GET(other_cpus)); + stop_cpus(PCPU_GET(other_cpus)); + db_printf("stopped_cpus=%x\n", stopped_cpus); +#endif + db_active++; if (ddb_mode) { cndbctl(TRUE); /* DDB active, unblank video */ db_trap(entry, a0); /* Where the work happens */ cndbctl(FALSE); /* DDB inactive */ } else gdb_handle_exception(&ddb_regs, entry, a0); db_active--; +#if 0 + restart_cpus(stopped_cpus); +#endif + splx(s); *regs = ddb_regs; /* * Tell caller "We HAVE handled the trap." */ return (1); } /* * Read bytes from kernel address space for debugger. */ void db_read_bytes(addr, size, data) vm_offset_t addr; register size_t size; register char *data; { register char *src; db_nofault = &db_jmpbuf; src = (char *)addr; while (size-- > 0) *data++ = *src++; db_nofault = 0; } /* * Write bytes to kernel address space for debugger. */ void db_write_bytes(addr, size, data) vm_offset_t addr; register size_t size; register char *data; { register char *dst; db_nofault = &db_jmpbuf; dst = (char *)addr; while (size-- > 0) *dst++ = *data++; alpha_pal_imb(); db_nofault = 0; } void Debugger(const char* msg) { printf("%s\n", msg); __asm("call_pal 0x81"); /* XXX bugchk */ } /* * Alpha-specific ddb commands: * * halt set halt bit in rpb and halt * reboot set reboot bit in rpb and halt */ DB_COMMAND(halt, db_mach_halt) { prom_halt(1); } DB_COMMAND(reboot, db_mach_reboot) { prom_halt(0); } /* * Map Alpha register numbers to trapframe/db_regs_t offsets. */ static int reg_to_frame[32] = { FRAME_V0, FRAME_T0, FRAME_T1, FRAME_T2, FRAME_T3, FRAME_T4, FRAME_T5, FRAME_T6, FRAME_T7, FRAME_S0, FRAME_S1, FRAME_S2, FRAME_S3, FRAME_S4, FRAME_S5, FRAME_S6, FRAME_A0, FRAME_A1, FRAME_A2, FRAME_A3, FRAME_A4, FRAME_A5, FRAME_T8, FRAME_T9, FRAME_T10, FRAME_T11, FRAME_RA, FRAME_T12, FRAME_AT, FRAME_GP, FRAME_SP, -1, /* zero */ }; u_long db_register_value(regs, regno) db_regs_t *regs; int regno; { if (regno > 31 || regno < 0) { db_printf(" **** STRANGE REGISTER NUMBER %d **** ", regno); return (0); } if (regno == 31) return (0); return (regs->tf_regs[reg_to_frame[regno]]); } /* * Support functions for software single-step. */ boolean_t db_inst_call(ins) int ins; { alpha_instruction insn; insn.bits = ins; return ((insn.branch_format.opcode == op_bsr) || ((insn.jump_format.opcode == op_j) && (insn.jump_format.action & 1))); } boolean_t db_inst_return(ins) int ins; { alpha_instruction insn; insn.bits = ins; return ((insn.jump_format.opcode == op_j) && (insn.jump_format.action == op_ret)); } boolean_t db_inst_trap_return(ins) int ins; { alpha_instruction insn; insn.bits = ins; return ((insn.pal_format.opcode == op_pal) && (insn.pal_format.function == PAL_OSF1_rti)); } boolean_t db_inst_branch(ins) int ins; { alpha_instruction insn; insn.bits = ins; switch (insn.branch_format.opcode) { case op_j: case op_br: case op_fbeq: case op_fblt: case op_fble: case op_fbne: case op_fbge: case op_fbgt: case op_blbc: case op_beq: case op_blt: case op_ble: case op_blbs: case op_bne: case op_bge: case op_bgt: return (TRUE); } return (FALSE); } boolean_t db_inst_unconditional_flow_transfer(ins) int ins; { alpha_instruction insn; insn.bits = ins; switch (insn.branch_format.opcode) { case op_j: case op_br: return (TRUE); case op_pal: switch (insn.pal_format.function) { case PAL_OSF1_retsys: case PAL_OSF1_rti: case PAL_OSF1_callsys: return (TRUE); } } return (FALSE); } #if 0 boolean_t db_inst_spill(ins, regn) int ins, regn; { alpha_instruction insn; insn.bits = ins; return ((insn.mem_format.opcode == op_stq) && (insn.mem_format.rd == regn)); } #endif boolean_t db_inst_load(ins) int ins; { alpha_instruction insn; insn.bits = ins; /* Loads. */ if (insn.mem_format.opcode == op_ldbu || insn.mem_format.opcode == op_ldq_u || insn.mem_format.opcode == op_ldwu) return (TRUE); if ((insn.mem_format.opcode >= op_ldf) && (insn.mem_format.opcode <= op_ldt)) return (TRUE); if ((insn.mem_format.opcode >= op_ldl) && (insn.mem_format.opcode <= op_ldq_l)) return (TRUE); /* Prefetches. */ if (insn.mem_format.opcode == op_special) { /* Note: MB is treated as a store. */ if ((insn.mem_format.displacement == (short)op_fetch) || (insn.mem_format.displacement == (short)op_fetch_m)) return (TRUE); } return (FALSE); } boolean_t db_inst_store(ins) int ins; { alpha_instruction insn; insn.bits = ins; /* Stores. */ if (insn.mem_format.opcode == op_stw || insn.mem_format.opcode == op_stb || insn.mem_format.opcode == op_stq_u) return (TRUE); if ((insn.mem_format.opcode >= op_stf) && (insn.mem_format.opcode <= op_stt)) return (TRUE); if ((insn.mem_format.opcode >= op_stl) && (insn.mem_format.opcode <= op_stq_c)) return (TRUE); /* Barriers. */ if (insn.mem_format.opcode == op_special) { if (insn.mem_format.displacement == op_mb) return (TRUE); } return (FALSE); } db_addr_t db_branch_taken(ins, pc, regs) int ins; db_addr_t pc; db_regs_t *regs; { alpha_instruction insn; db_addr_t newpc; insn.bits = ins; switch (insn.branch_format.opcode) { /* * Jump format: target PC is (contents of instruction's "RB") & ~3. */ case op_j: newpc = db_register_value(regs, insn.jump_format.rs) & ~3; break; /* * Branch format: target PC is * (new PC) + (4 * sign-ext(displacement)). */ case op_br: case op_fbeq: case op_fblt: case op_fble: case op_bsr: case op_fbne: case op_fbge: case op_fbgt: case op_blbc: case op_beq: case op_blt: case op_ble: case op_blbs: case op_bne: case op_bge: case op_bgt: newpc = (insn.branch_format.displacement << 2) + (pc + 4); break; default: printf("DDB: db_inst_branch_taken on non-branch!\n"); newpc = pc; /* XXX */ } return (newpc); } + +#ifdef KTR + +static struct { + int cur; + int first; +} tstate[NCPUS]; +static struct timespec lastt; +static int db_tcpu = 0xff; +static int db_mach_vtrace(void); + +DB_COMMAND(tbuf, db_mach_tbuf) +{ + int i; + + for (i = 0; i < NCPUS; i++) { + struct ktr_entry *k1, *ck, *kend; + struct globaldata *pp; + struct timespec newk; + + if ((pp = globaldata_find(i)) == NULL) + continue; + + k1 = (struct ktr_entry *)pp->gd_ktr_buf; + ck = k1; + timespecclear(&newk); + kend = (struct ktr_entry *)(pp->gd_ktr_buf + KTR_SIZE); + while (k1 != kend) { + if (timespecisset(&k1->ktr_tv) && + timespeccmp(&k1->ktr_tv, &newk, >)) { + newk = k1->ktr_tv; + ck = k1; + } + k1++; + } + tstate[i].cur = ((uintptr_t)(ck) - + (uintptr_t)pp->gd_ktr_buf) & (KTR_ESIZE-1); + tstate[i].first = tstate[i].cur | 0x80000000; + } + timespecclear(&lastt); + db_mach_vtrace(); + return; +} + +/* + * Print all trace entries + */ +DB_COMMAND(tall, db_mach_tall) +{ + int c; + + db_mach_tbuf(addr, have_addr, count, modif); + while (db_mach_vtrace()) { + c = cncheckc(); + if (c != -1) + break; + } + return; +} + +DB_COMMAND(tnext, db_mach_tnext) +{ + db_mach_vtrace(); +} + +static int +db_mach_vtrace(void) +{ + struct ktr_entry *kp; + struct ktr_entry *kpt; + char *d; + int i; + int wcpu; + struct globaldata *pp; + struct timespec ts; + + /* Pick the newest trace entry from all CPU's */ + kp = NULL; + wcpu = 0; + for (i = 0; i < NCPUS; i++) { + if (db_tcpu != 0xff && i != db_tcpu) + continue; + if (!(pp = globaldata_find(i))) + continue; + if (tstate[i].cur == tstate[i].first) + continue; + kpt = (struct ktr_entry *)((char *)pp->gd_ktr_buf + + tstate[i].cur); + if (!kp || timespeccmp(&kp->ktr_tv, &kpt->ktr_tv, <)) { + kp = kpt; + wcpu = i; + } + } + if (!kp) { + db_printf("--- End of trace buffer ---\n"); + return (0); + } + + d = kp->ktr_desc; + if (d == NULL) + d = "*** Empty ***"; +#if 0 + if (kernacc(d, 80, B_READ) == 0) + d = "*** Corrupt entry ***"; +#endif + else if (lastt.tv_sec == 0) { + db_printf("Newest entry at clock %d.%06ld\n", + kp->ktr_tv.tv_sec, + kp->ktr_tv.tv_nsec / 1000); + lastt = kp->ktr_tv; + } + db_printf("\r%x %3x ", wcpu, tstate[wcpu].cur >> KTR_SHFT); + ts = lastt; + /* timespecsub(&ts, &kp->ktr_tv); */ + db_printf("%4d.%06ld: ", ts.tv_sec, ts.tv_nsec / 1000); + lastt = kp->ktr_tv; + db_printf(d, kp->ktr_parm1, kp->ktr_parm2, kp->ktr_parm3, + kp->ktr_parm4, kp->ktr_parm5); +#if 0 + if (kdebug_vflag) + db_printf(" p1=%x p2=%x p3=%x p4=%x p5=%x", (u_int)kp->ktr_parm1, + (u_int)kp->ktr_parm2, (u_int)kp->ktr_parm3, + (u_int)kp->ktr_parm4, (u_int)kp->ktr_parm5); +#endif + db_printf("\n"); + tstate[wcpu].first &= ~0x80000000; + tstate[wcpu].cur = (tstate[wcpu].cur - sizeof(struct ktr_entry)) & + (KTR_ESIZE - 1); + return (1); +} + +#endif diff --git a/sys/amd64/amd64/db_interface.c b/sys/amd64/amd64/db_interface.c index b3dd2922d6f2..a801301a79cc 100644 --- a/sys/amd64/amd64/db_interface.c +++ b/sys/amd64/amd64/db_interface.c @@ -1,321 +1,430 @@ /* * 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 * 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. * * $FreeBSD$ */ /* * Interface to new debugger. */ #include #include #include #include +#include +#include #include #ifdef SMP #include #include /** CPUSTOP_ON_DDBBREAK */ #endif #include #include #include +#include +#include +#include #include static jmp_buf *db_nofault = 0; extern jmp_buf db_jmpbuf; extern void gdb_handle_exception __P((db_regs_t *, int, int)); int db_active; db_regs_t ddb_regs; static jmp_buf db_global_jmpbuf; static int db_global_jmpbuf_valid; #ifdef __GNUC__ #define rss() ({u_short ss; __asm __volatile("mov %%ss,%0" : "=r" (ss)); ss;}) #endif /* * kdb_trap - field a TRACE or BPT trap */ int kdb_trap(type, code, regs) int type, code; register struct i386_saved_state *regs; { volatile int ddb_mode = !(boothowto & RB_GDB); /* * XXX try to do nothing if the console is in graphics mode. * Handle trace traps (and hardware breakpoints...) by ignoring * them except for forgetting about them. Return 0 for other * traps to say that we haven't done anything. The trap handler * will usually panic. We should handle breakpoint traps for * our breakpoints by disarming our breakpoints and fixing up * %eip. */ if (cons_unavail && ddb_mode) { if (type == T_TRCTRAP) { regs->tf_eflags &= ~PSL_T; return (1); } return (0); } switch (type) { case T_BPTFLT: /* breakpoint */ case T_TRCTRAP: /* debug exception */ break; default: /* * XXX this is almost useless now. In most cases, * trap_fatal() has already printed a much more verbose * message. However, it is dangerous to print things in * trap_fatal() - printf() might be reentered and trap. * The debugger should be given control first. */ if (ddb_mode) db_printf("kernel: type %d trap, code=%x\n", type, code); if (db_nofault) { jmp_buf *no_fault = db_nofault; db_nofault = 0; longjmp(*no_fault, 1); } } /* * This handles unexpected traps in ddb commands, including calls to * non-ddb functions. db_nofault only applies to memory accesses by * internal ddb commands. */ if (db_global_jmpbuf_valid) longjmp(db_global_jmpbuf, 1); /* * XXX We really should switch to a local stack here. */ ddb_regs = *regs; /* * If in kernel mode, esp and ss are not saved, so dummy them up. */ if (ISPL(regs->tf_cs) == 0) { ddb_regs.tf_esp = (int)®s->tf_esp; ddb_regs.tf_ss = rss(); } #ifdef SMP #ifdef CPUSTOP_ON_DDBBREAK #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf("\nCPU%d stopping CPUs: 0x%08x\n", cpuid, other_cpus); + db_printf("\nCPU%d stopping CPUs: 0x%08x...", cpuid, other_cpus); #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ /* We stop all CPUs except ourselves (obviously) */ stop_cpus(other_cpus); #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf(" stopped\n"); + db_printf(" stopped.\n"); #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ #endif /* CPUSTOP_ON_DDBBREAK */ #endif /* SMP */ (void) setjmp(db_global_jmpbuf); db_global_jmpbuf_valid = TRUE; db_active++; if (ddb_mode) { cndbctl(TRUE); db_trap(type, code); cndbctl(FALSE); } else gdb_handle_exception(&ddb_regs, type, code); db_active--; db_global_jmpbuf_valid = FALSE; #ifdef SMP #ifdef CPUSTOP_ON_DDBBREAK #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf("\nCPU%d restarting CPUs: 0x%08x\n", cpuid, stopped_cpus); + db_printf("\nCPU%d restarting CPUs: 0x%08x...", cpuid, stopped_cpus); #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ /* Restart all the CPUs we previously stopped */ if (stopped_cpus != other_cpus && smp_started != 0) { db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n", other_cpus, stopped_cpus); panic("stop_cpus() failed"); } restart_cpus(stopped_cpus); #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf(" restarted\n"); + db_printf(" restarted.\n"); #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ #endif /* CPUSTOP_ON_DDBBREAK */ #endif /* SMP */ regs->tf_eip = ddb_regs.tf_eip; regs->tf_eflags = ddb_regs.tf_eflags; regs->tf_eax = ddb_regs.tf_eax; regs->tf_ecx = ddb_regs.tf_ecx; regs->tf_edx = ddb_regs.tf_edx; regs->tf_ebx = ddb_regs.tf_ebx; /* * If in user mode, the saved ESP and SS were valid, restore them. */ if (ISPL(regs->tf_cs)) { regs->tf_esp = ddb_regs.tf_esp; regs->tf_ss = ddb_regs.tf_ss & 0xffff; } regs->tf_ebp = ddb_regs.tf_ebp; regs->tf_esi = ddb_regs.tf_esi; regs->tf_edi = ddb_regs.tf_edi; regs->tf_es = ddb_regs.tf_es & 0xffff; regs->tf_fs = ddb_regs.tf_fs & 0xffff; regs->tf_cs = ddb_regs.tf_cs & 0xffff; regs->tf_ds = ddb_regs.tf_ds & 0xffff; return (1); } /* * Read bytes from kernel address space for debugger. */ void db_read_bytes(addr, size, data) vm_offset_t addr; register size_t size; register char *data; { register char *src; db_nofault = &db_jmpbuf; src = (char *)addr; while (size-- > 0) *data++ = *src++; db_nofault = 0; } /* * Write bytes to kernel address space for debugger. */ void db_write_bytes(addr, size, data) vm_offset_t addr; register size_t size; register char *data; { register char *dst; unsigned *ptep0 = NULL; unsigned oldmap0 = 0; vm_offset_t addr1; unsigned *ptep1 = NULL; unsigned oldmap1 = 0; db_nofault = &db_jmpbuf; if (addr > trunc_page((vm_offset_t)btext) - size && addr < round_page((vm_offset_t)etext)) { ptep0 = pmap_pte(kernel_pmap, addr); oldmap0 = *ptep0; *ptep0 |= PG_RW; /* Map another page if the data crosses a page boundary. */ if ((*ptep0 & PG_PS) == 0) { addr1 = trunc_page(addr + size - 1); if (trunc_page(addr) != addr1) { ptep1 = pmap_pte(kernel_pmap, addr1); oldmap1 = *ptep1; *ptep1 |= PG_RW; } } else { addr1 = trunc_4mpage(addr + size - 1); if (trunc_4mpage(addr) != addr1) { ptep1 = pmap_pte(kernel_pmap, addr1); oldmap1 = *ptep1; *ptep1 |= PG_RW; } } invltlb(); } dst = (char *)addr; while (size-- > 0) *dst++ = *data++; db_nofault = 0; if (ptep0) { *ptep0 = oldmap0; if (ptep1) *ptep1 = oldmap1; invltlb(); } } /* * XXX * Move this to machdep.c and allow it to be called if any debugger is * installed. */ void Debugger(msg) const char *msg; { - static volatile u_char in_Debugger; - + static volatile u_char in_Debugger; + int flags; /* * XXX * Do nothing if the console is in graphics mode. This is * OK if the call is for the debugger hotkey but not if the call * is a weak form of panicing. */ if (cons_unavail && !(boothowto & RB_GDB)) return; if (!in_Debugger) { + flags = save_intr(); + disable_intr(); in_Debugger = 1; db_printf("Debugger(\"%s\")\n", msg); breakpoint(); in_Debugger = 0; + restore_intr(flags); + } +} + +#if defined(KTR) + +struct tstate { + int cur; + int first; +}; +static struct tstate tstate; +static struct timespec lastt; +static int db_mach_vtrace(void); + +DB_COMMAND(tbuf, db_mach_tbuf) +{ + struct ktr_entry *k1, *ck, *kend; + struct timespec newk; + + k1 = ktr_buf; + ck = k1; + timespecclear(&newk); + kend = ktr_buf + KTR_ENTRIES; + while (k1 != kend) { + if (timespecisset(&k1->ktr_tv) && + timespeccmp(&k1->ktr_tv, &newk, >)) { + newk = k1->ktr_tv; + ck = k1; + } + k1++; } + tstate.cur = ck - ktr_buf; + tstate.first = tstate.cur | 0x80000000; + timespecclear(&lastt); + db_mach_vtrace(); + + return; +} + +DB_COMMAND(tall, db_mach_tall) +{ + int c; + + db_mach_tbuf(addr, have_addr, count, modif); + while (db_mach_vtrace()) { + c = cncheckc(); + if (c != -1) + break; + } + + return; } + +DB_COMMAND(tnext, db_mach_tnext) +{ + db_mach_vtrace(); +} + +static int +db_mach_vtrace(void) +{ + struct ktr_entry *kp; + struct timespec ts; + char *d; + + kp = NULL; + if (tstate.cur != tstate.first) + kp = ktr_buf + tstate.cur; + else + kp = NULL; + + if (!kp) { + db_printf("--- End of trace buffer ---\n"); + return (0); + } + + d = kp->ktr_desc; + if (d == NULL) + d = "*** Empty ***"; + else if (lastt.tv_sec == 0) { + db_printf("Newest entry at clock %ld.%06ld\n", + kp->ktr_tv.tv_sec, + kp->ktr_tv.tv_nsec / 1000); + lastt = kp->ktr_tv; + } + ts = lastt; + db_printf("%4ld.%06ld: ", ts.tv_sec, ts.tv_nsec / 1000); + lastt = kp->ktr_tv; +#ifdef KTR_EXTEND + db_printf("cpu%d %s.%d\t%s", kp->ktr_cpu, kp->ktr_filename, + kp->ktr_line, kp->ktr_desc); +#else + db_printf(d, kp->ktr_parm1, kp->ktr_parm2, kp->ktr_parm3, + kp->ktr_parm4, kp->ktr_parm5); +#endif + db_printf("\n"); + tstate.first &= ~0x80000000; + if (--tstate.cur < 0) + tstate.cur = KTR_ENTRIES - 1; + + return (1); +} + +#endif diff --git a/sys/i386/i386/db_interface.c b/sys/i386/i386/db_interface.c index b3dd2922d6f2..a801301a79cc 100644 --- a/sys/i386/i386/db_interface.c +++ b/sys/i386/i386/db_interface.c @@ -1,321 +1,430 @@ /* * 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 * 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. * * $FreeBSD$ */ /* * Interface to new debugger. */ #include #include #include #include +#include +#include #include #ifdef SMP #include #include /** CPUSTOP_ON_DDBBREAK */ #endif #include #include #include +#include +#include +#include #include static jmp_buf *db_nofault = 0; extern jmp_buf db_jmpbuf; extern void gdb_handle_exception __P((db_regs_t *, int, int)); int db_active; db_regs_t ddb_regs; static jmp_buf db_global_jmpbuf; static int db_global_jmpbuf_valid; #ifdef __GNUC__ #define rss() ({u_short ss; __asm __volatile("mov %%ss,%0" : "=r" (ss)); ss;}) #endif /* * kdb_trap - field a TRACE or BPT trap */ int kdb_trap(type, code, regs) int type, code; register struct i386_saved_state *regs; { volatile int ddb_mode = !(boothowto & RB_GDB); /* * XXX try to do nothing if the console is in graphics mode. * Handle trace traps (and hardware breakpoints...) by ignoring * them except for forgetting about them. Return 0 for other * traps to say that we haven't done anything. The trap handler * will usually panic. We should handle breakpoint traps for * our breakpoints by disarming our breakpoints and fixing up * %eip. */ if (cons_unavail && ddb_mode) { if (type == T_TRCTRAP) { regs->tf_eflags &= ~PSL_T; return (1); } return (0); } switch (type) { case T_BPTFLT: /* breakpoint */ case T_TRCTRAP: /* debug exception */ break; default: /* * XXX this is almost useless now. In most cases, * trap_fatal() has already printed a much more verbose * message. However, it is dangerous to print things in * trap_fatal() - printf() might be reentered and trap. * The debugger should be given control first. */ if (ddb_mode) db_printf("kernel: type %d trap, code=%x\n", type, code); if (db_nofault) { jmp_buf *no_fault = db_nofault; db_nofault = 0; longjmp(*no_fault, 1); } } /* * This handles unexpected traps in ddb commands, including calls to * non-ddb functions. db_nofault only applies to memory accesses by * internal ddb commands. */ if (db_global_jmpbuf_valid) longjmp(db_global_jmpbuf, 1); /* * XXX We really should switch to a local stack here. */ ddb_regs = *regs; /* * If in kernel mode, esp and ss are not saved, so dummy them up. */ if (ISPL(regs->tf_cs) == 0) { ddb_regs.tf_esp = (int)®s->tf_esp; ddb_regs.tf_ss = rss(); } #ifdef SMP #ifdef CPUSTOP_ON_DDBBREAK #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf("\nCPU%d stopping CPUs: 0x%08x\n", cpuid, other_cpus); + db_printf("\nCPU%d stopping CPUs: 0x%08x...", cpuid, other_cpus); #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ /* We stop all CPUs except ourselves (obviously) */ stop_cpus(other_cpus); #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf(" stopped\n"); + db_printf(" stopped.\n"); #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ #endif /* CPUSTOP_ON_DDBBREAK */ #endif /* SMP */ (void) setjmp(db_global_jmpbuf); db_global_jmpbuf_valid = TRUE; db_active++; if (ddb_mode) { cndbctl(TRUE); db_trap(type, code); cndbctl(FALSE); } else gdb_handle_exception(&ddb_regs, type, code); db_active--; db_global_jmpbuf_valid = FALSE; #ifdef SMP #ifdef CPUSTOP_ON_DDBBREAK #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf("\nCPU%d restarting CPUs: 0x%08x\n", cpuid, stopped_cpus); + db_printf("\nCPU%d restarting CPUs: 0x%08x...", cpuid, stopped_cpus); #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ /* Restart all the CPUs we previously stopped */ if (stopped_cpus != other_cpus && smp_started != 0) { db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n", other_cpus, stopped_cpus); panic("stop_cpus() failed"); } restart_cpus(stopped_cpus); #if defined(VERBOSE_CPUSTOP_ON_DDBBREAK) - db_printf(" restarted\n"); + db_printf(" restarted.\n"); #endif /* VERBOSE_CPUSTOP_ON_DDBBREAK */ #endif /* CPUSTOP_ON_DDBBREAK */ #endif /* SMP */ regs->tf_eip = ddb_regs.tf_eip; regs->tf_eflags = ddb_regs.tf_eflags; regs->tf_eax = ddb_regs.tf_eax; regs->tf_ecx = ddb_regs.tf_ecx; regs->tf_edx = ddb_regs.tf_edx; regs->tf_ebx = ddb_regs.tf_ebx; /* * If in user mode, the saved ESP and SS were valid, restore them. */ if (ISPL(regs->tf_cs)) { regs->tf_esp = ddb_regs.tf_esp; regs->tf_ss = ddb_regs.tf_ss & 0xffff; } regs->tf_ebp = ddb_regs.tf_ebp; regs->tf_esi = ddb_regs.tf_esi; regs->tf_edi = ddb_regs.tf_edi; regs->tf_es = ddb_regs.tf_es & 0xffff; regs->tf_fs = ddb_regs.tf_fs & 0xffff; regs->tf_cs = ddb_regs.tf_cs & 0xffff; regs->tf_ds = ddb_regs.tf_ds & 0xffff; return (1); } /* * Read bytes from kernel address space for debugger. */ void db_read_bytes(addr, size, data) vm_offset_t addr; register size_t size; register char *data; { register char *src; db_nofault = &db_jmpbuf; src = (char *)addr; while (size-- > 0) *data++ = *src++; db_nofault = 0; } /* * Write bytes to kernel address space for debugger. */ void db_write_bytes(addr, size, data) vm_offset_t addr; register size_t size; register char *data; { register char *dst; unsigned *ptep0 = NULL; unsigned oldmap0 = 0; vm_offset_t addr1; unsigned *ptep1 = NULL; unsigned oldmap1 = 0; db_nofault = &db_jmpbuf; if (addr > trunc_page((vm_offset_t)btext) - size && addr < round_page((vm_offset_t)etext)) { ptep0 = pmap_pte(kernel_pmap, addr); oldmap0 = *ptep0; *ptep0 |= PG_RW; /* Map another page if the data crosses a page boundary. */ if ((*ptep0 & PG_PS) == 0) { addr1 = trunc_page(addr + size - 1); if (trunc_page(addr) != addr1) { ptep1 = pmap_pte(kernel_pmap, addr1); oldmap1 = *ptep1; *ptep1 |= PG_RW; } } else { addr1 = trunc_4mpage(addr + size - 1); if (trunc_4mpage(addr) != addr1) { ptep1 = pmap_pte(kernel_pmap, addr1); oldmap1 = *ptep1; *ptep1 |= PG_RW; } } invltlb(); } dst = (char *)addr; while (size-- > 0) *dst++ = *data++; db_nofault = 0; if (ptep0) { *ptep0 = oldmap0; if (ptep1) *ptep1 = oldmap1; invltlb(); } } /* * XXX * Move this to machdep.c and allow it to be called if any debugger is * installed. */ void Debugger(msg) const char *msg; { - static volatile u_char in_Debugger; - + static volatile u_char in_Debugger; + int flags; /* * XXX * Do nothing if the console is in graphics mode. This is * OK if the call is for the debugger hotkey but not if the call * is a weak form of panicing. */ if (cons_unavail && !(boothowto & RB_GDB)) return; if (!in_Debugger) { + flags = save_intr(); + disable_intr(); in_Debugger = 1; db_printf("Debugger(\"%s\")\n", msg); breakpoint(); in_Debugger = 0; + restore_intr(flags); + } +} + +#if defined(KTR) + +struct tstate { + int cur; + int first; +}; +static struct tstate tstate; +static struct timespec lastt; +static int db_mach_vtrace(void); + +DB_COMMAND(tbuf, db_mach_tbuf) +{ + struct ktr_entry *k1, *ck, *kend; + struct timespec newk; + + k1 = ktr_buf; + ck = k1; + timespecclear(&newk); + kend = ktr_buf + KTR_ENTRIES; + while (k1 != kend) { + if (timespecisset(&k1->ktr_tv) && + timespeccmp(&k1->ktr_tv, &newk, >)) { + newk = k1->ktr_tv; + ck = k1; + } + k1++; } + tstate.cur = ck - ktr_buf; + tstate.first = tstate.cur | 0x80000000; + timespecclear(&lastt); + db_mach_vtrace(); + + return; +} + +DB_COMMAND(tall, db_mach_tall) +{ + int c; + + db_mach_tbuf(addr, have_addr, count, modif); + while (db_mach_vtrace()) { + c = cncheckc(); + if (c != -1) + break; + } + + return; } + +DB_COMMAND(tnext, db_mach_tnext) +{ + db_mach_vtrace(); +} + +static int +db_mach_vtrace(void) +{ + struct ktr_entry *kp; + struct timespec ts; + char *d; + + kp = NULL; + if (tstate.cur != tstate.first) + kp = ktr_buf + tstate.cur; + else + kp = NULL; + + if (!kp) { + db_printf("--- End of trace buffer ---\n"); + return (0); + } + + d = kp->ktr_desc; + if (d == NULL) + d = "*** Empty ***"; + else if (lastt.tv_sec == 0) { + db_printf("Newest entry at clock %ld.%06ld\n", + kp->ktr_tv.tv_sec, + kp->ktr_tv.tv_nsec / 1000); + lastt = kp->ktr_tv; + } + ts = lastt; + db_printf("%4ld.%06ld: ", ts.tv_sec, ts.tv_nsec / 1000); + lastt = kp->ktr_tv; +#ifdef KTR_EXTEND + db_printf("cpu%d %s.%d\t%s", kp->ktr_cpu, kp->ktr_filename, + kp->ktr_line, kp->ktr_desc); +#else + db_printf(d, kp->ktr_parm1, kp->ktr_parm2, kp->ktr_parm3, + kp->ktr_parm4, kp->ktr_parm5); +#endif + db_printf("\n"); + tstate.first &= ~0x80000000; + if (--tstate.cur < 0) + tstate.cur = KTR_ENTRIES - 1; + + return (1); +} + +#endif diff --git a/sys/kern/kern_ktr.c b/sys/kern/kern_ktr.c new file mode 100644 index 000000000000..486379db5620 --- /dev/null +++ b/sys/kern/kern_ktr.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000 + * John Baldwin . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * This module holds the global variables used by KTR. + */ + +#include +#include +#include +#include +#include + +#ifdef KTR_EXTEND +/* + * This variable is used only by gdb to work out what fields are in + * ktr_entry. + */ +int ktr_extend = 1; +SYSCTL_INT(_debug, OID_AUTO, ktr_extend, CTLFLAG_RD, &ktr_extend, 1, ""); +#else +int ktr_extend = 0; +SYSCTL_INT(_debug, OID_AUTO, ktr_extend, CTLFLAG_RD, &ktr_extend, 0, ""); +#endif + +int ktr_cpumask = KTR_CPUMASK; +SYSCTL_INT(_debug, OID_AUTO, ktr_cpumask, CTLFLAG_RW, &ktr_cpumask, KTR_CPUMASK, ""); + +int ktr_mask = KTR_MASK; +SYSCTL_INT(_debug, OID_AUTO, ktr_mask, CTLFLAG_RW, &ktr_mask, KTR_MASK, ""); + +int ktr_entries = KTR_ENTRIES; +SYSCTL_INT(_debug, OID_AUTO, ktr_entries, CTLFLAG_RD, &ktr_entries, KTR_ENTRIES, ""); + +volatile int ktr_idx = 0; +struct ktr_entry ktr_buf[KTR_ENTRIES]; diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index ef82c6cbe37d..e51f8d10fee7 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -1,540 +1,540 @@ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93 * $FreeBSD$ */ #include "opt_ktrace.h" #include #include #include #include #include #include #include #include #include #include #include #include #include static MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE"); #ifdef KTRACE static struct ktr_header *ktrgetheader __P((int type)); static void ktrwrite __P((struct vnode *, struct ktr_header *, struct uio *)); static int ktrcanset __P((struct proc *,struct proc *)); static int ktrsetchildren __P((struct proc *,struct proc *,int,int,struct vnode *)); static int ktrops __P((struct proc *,struct proc *,int,int,struct vnode *)); static struct ktr_header * ktrgetheader(type) int type; { register struct ktr_header *kth; struct proc *p = curproc; /* XXX */ MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), M_KTRACE, M_WAITOK); kth->ktr_type = type; microtime(&kth->ktr_time); kth->ktr_pid = p->p_pid; bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN + 1); return (kth); } void ktrsyscall(vp, code, narg, args) struct vnode *vp; int code, narg; register_t args[]; { struct ktr_header *kth; struct ktr_syscall *ktp; register int len = offsetof(struct ktr_syscall, ktr_args) + (narg * sizeof(register_t)); struct proc *p = curproc; /* XXX */ register_t *argp; int i; p->p_traceflag |= KTRFAC_ACTIVE; kth = ktrgetheader(KTR_SYSCALL); MALLOC(ktp, struct ktr_syscall *, len, M_KTRACE, M_WAITOK); ktp->ktr_code = code; ktp->ktr_narg = narg; argp = &ktp->ktr_args[0]; for (i = 0; i < narg; i++) *argp++ = args[i]; - kth->ktr_buf = (caddr_t)ktp; + kth->ktr_buffer = (caddr_t)ktp; kth->ktr_len = len; ktrwrite(vp, kth, NULL); FREE(ktp, M_KTRACE); FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } void ktrsysret(vp, code, error, retval) struct vnode *vp; int code, error; register_t retval; { struct ktr_header *kth; struct ktr_sysret ktp; struct proc *p = curproc; /* XXX */ p->p_traceflag |= KTRFAC_ACTIVE; kth = ktrgetheader(KTR_SYSRET); ktp.ktr_code = code; ktp.ktr_error = error; ktp.ktr_retval = retval; /* what about val2 ? */ - kth->ktr_buf = (caddr_t)&ktp; + kth->ktr_buffer = (caddr_t)&ktp; kth->ktr_len = sizeof(struct ktr_sysret); ktrwrite(vp, kth, NULL); FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } void ktrnamei(vp, path) struct vnode *vp; char *path; { struct ktr_header *kth; struct proc *p = curproc; /* XXX */ p->p_traceflag |= KTRFAC_ACTIVE; kth = ktrgetheader(KTR_NAMEI); kth->ktr_len = strlen(path); - kth->ktr_buf = path; + kth->ktr_buffer = path; ktrwrite(vp, kth, NULL); FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } void ktrgenio(vp, fd, rw, uio, error) struct vnode *vp; int fd; enum uio_rw rw; struct uio *uio; int error; { struct ktr_header *kth; struct ktr_genio ktg; struct proc *p = curproc; /* XXX */ if (error) return; p->p_traceflag |= KTRFAC_ACTIVE; kth = ktrgetheader(KTR_GENIO); ktg.ktr_fd = fd; ktg.ktr_rw = rw; - kth->ktr_buf = (caddr_t)&ktg; + kth->ktr_buffer = (caddr_t)&ktg; kth->ktr_len = sizeof(struct ktr_genio); uio->uio_offset = 0; uio->uio_rw = UIO_WRITE; ktrwrite(vp, kth, uio); FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } void ktrpsig(vp, sig, action, mask, code) struct vnode *vp; int sig; sig_t action; sigset_t *mask; int code; { struct ktr_header *kth; struct ktr_psig kp; struct proc *p = curproc; /* XXX */ p->p_traceflag |= KTRFAC_ACTIVE; kth = ktrgetheader(KTR_PSIG); kp.signo = (char)sig; kp.action = action; kp.mask = *mask; kp.code = code; - kth->ktr_buf = (caddr_t)&kp; + kth->ktr_buffer = (caddr_t)&kp; kth->ktr_len = sizeof (struct ktr_psig); ktrwrite(vp, kth, NULL); FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } void ktrcsw(vp, out, user) struct vnode *vp; int out, user; { struct ktr_header *kth; struct ktr_csw kc; struct proc *p = curproc; /* XXX */ p->p_traceflag |= KTRFAC_ACTIVE; kth = ktrgetheader(KTR_CSW); kc.out = out; kc.user = user; - kth->ktr_buf = (caddr_t)&kc; + kth->ktr_buffer = (caddr_t)&kc; kth->ktr_len = sizeof (struct ktr_csw); ktrwrite(vp, kth, NULL); FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } #endif /* Interface and common routines */ /* * ktrace system call */ #ifndef _SYS_SYSPROTO_H_ struct ktrace_args { char *fname; int ops; int facs; int pid; }; #endif /* ARGSUSED */ int ktrace(curp, uap) struct proc *curp; register struct ktrace_args *uap; { #ifdef KTRACE register struct vnode *vp = NULL; register struct proc *p; struct pgrp *pg; int facs = uap->facs & ~KTRFAC_ROOT; int ops = KTROP(uap->ops); int descend = uap->ops & KTRFLAG_DESCEND; int ret = 0; int flags, error = 0; struct nameidata nd; curp->p_traceflag |= KTRFAC_ACTIVE; if (ops != KTROP_CLEAR) { /* * an operation which requires a file argument. */ NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, curp); flags = FREAD | FWRITE | O_NOFOLLOW; error = vn_open(&nd, &flags, 0); if (error) { curp->p_traceflag &= ~KTRFAC_ACTIVE; return (error); } NDFREE(&nd, NDF_ONLY_PNBUF); vp = nd.ni_vp; VOP_UNLOCK(vp, 0, curp); if (vp->v_type != VREG) { (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); curp->p_traceflag &= ~KTRFAC_ACTIVE; return (EACCES); } } /* * Clear all uses of the tracefile */ if (ops == KTROP_CLEARFILE) { LIST_FOREACH(p, &allproc, p_list) { if (p->p_tracep == vp) { if (ktrcanset(curp, p)) { p->p_tracep = NULL; p->p_traceflag = 0; (void) vn_close(vp, FREAD|FWRITE, p->p_ucred, p); } else error = EPERM; } } goto done; } /* * need something to (un)trace (XXX - why is this here?) */ if (!facs) { error = EINVAL; goto done; } /* * do it */ if (uap->pid < 0) { /* * by process group */ pg = pgfind(-uap->pid); if (pg == NULL) { error = ESRCH; goto done; } LIST_FOREACH(p, &pg->pg_members, p_pglist) if (descend) ret |= ktrsetchildren(curp, p, ops, facs, vp); else ret |= ktrops(curp, p, ops, facs, vp); } else { /* * by pid */ p = pfind(uap->pid); if (p == NULL) { error = ESRCH; goto done; } if (descend) ret |= ktrsetchildren(curp, p, ops, facs, vp); else ret |= ktrops(curp, p, ops, facs, vp); } if (!ret) error = EPERM; done: if (vp != NULL) (void) vn_close(vp, FWRITE, curp->p_ucred, curp); curp->p_traceflag &= ~KTRFAC_ACTIVE; return (error); #else return ENOSYS; #endif } /* * utrace system call */ /* ARGSUSED */ int utrace(curp, uap) struct proc *curp; register struct utrace_args *uap; { #ifdef KTRACE struct ktr_header *kth; struct proc *p = curproc; /* XXX */ register caddr_t cp; if (!KTRPOINT(p, KTR_USER)) return (0); p->p_traceflag |= KTRFAC_ACTIVE; kth = ktrgetheader(KTR_USER); MALLOC(cp, caddr_t, uap->len, M_KTRACE, M_WAITOK); if (!copyin(uap->addr, cp, uap->len)) { - kth->ktr_buf = cp; + kth->ktr_buffer = cp; kth->ktr_len = uap->len; ktrwrite(p->p_tracep, kth, NULL); } FREE(kth, M_KTRACE); FREE(cp, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; return (0); #else return (ENOSYS); #endif } #ifdef KTRACE static int ktrops(curp, p, ops, facs, vp) struct proc *p, *curp; int ops, facs; struct vnode *vp; { if (!ktrcanset(curp, p)) return (0); if (ops == KTROP_SET) { if (p->p_tracep != vp) { /* * if trace file already in use, relinquish */ if (p->p_tracep != NULL) vrele(p->p_tracep); VREF(vp); p->p_tracep = vp; } p->p_traceflag |= facs; if (curp->p_ucred->cr_uid == 0) p->p_traceflag |= KTRFAC_ROOT; } else { /* KTROP_CLEAR */ if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { /* no more tracing */ p->p_traceflag = 0; if (p->p_tracep != NULL) { vrele(p->p_tracep); p->p_tracep = NULL; } } } return (1); } static int ktrsetchildren(curp, top, ops, facs, vp) struct proc *curp, *top; int ops, facs; struct vnode *vp; { register struct proc *p; register int ret = 0; p = top; for (;;) { ret |= ktrops(curp, p, ops, facs, vp); /* * If this process has children, descend to them next, * otherwise do any siblings, and if done with this level, * follow back up the tree (but not past top). */ if (!LIST_EMPTY(&p->p_children)) p = LIST_FIRST(&p->p_children); else for (;;) { if (p == top) return (ret); if (LIST_NEXT(p, p_sibling)) { p = LIST_NEXT(p, p_sibling); break; } p = p->p_pptr; } } /*NOTREACHED*/ } static void ktrwrite(vp, kth, uio) struct vnode *vp; register struct ktr_header *kth; struct uio *uio; { struct uio auio; struct iovec aiov[2]; struct proc *p = curproc; /* XXX */ struct mount *mp; int error; if (vp == NULL) return; auio.uio_iov = &aiov[0]; auio.uio_offset = 0; auio.uio_segflg = UIO_SYSSPACE; auio.uio_rw = UIO_WRITE; aiov[0].iov_base = (caddr_t)kth; aiov[0].iov_len = sizeof(struct ktr_header); auio.uio_resid = sizeof(struct ktr_header); auio.uio_iovcnt = 1; auio.uio_procp = curproc; if (kth->ktr_len > 0) { auio.uio_iovcnt++; - aiov[1].iov_base = kth->ktr_buf; + aiov[1].iov_base = kth->ktr_buffer; aiov[1].iov_len = kth->ktr_len; auio.uio_resid += kth->ktr_len; if (uio != NULL) kth->ktr_len += uio->uio_resid; } vn_start_write(vp, &mp, V_WAIT); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); (void)VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, p->p_ucred); if (error == 0 && uio != NULL) { (void)VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, p->p_ucred); } VOP_UNLOCK(vp, 0, p); vn_finished_write(mp); if (!error) return; /* * If error encountered, give up tracing on this vnode. */ log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", error); LIST_FOREACH(p, &allproc, p_list) { if (p->p_tracep == vp) { p->p_tracep = NULL; p->p_traceflag = 0; vrele(vp); } } } /* * Return true if caller has permission to set the ktracing state * of target. Essentially, the target can't possess any * more permissions than the caller. KTRFAC_ROOT signifies that * root previously set the tracing status on the target process, and * so, only root may further change it. * * XXX: These checks are stronger than for ptrace() * * TODO: check groups. use caller effective gid. */ static int ktrcanset(callp, targetp) struct proc *callp, *targetp; { register struct pcred *caller = callp->p_cred; register struct pcred *target = targetp->p_cred; if (!PRISON_CHECK(callp, targetp)) return (0); if ((caller->pc_ucred->cr_uid == target->p_ruid && target->p_ruid == target->p_svuid && caller->p_rgid == target->p_rgid && /* XXX */ target->p_rgid == target->p_svgid && (targetp->p_traceflag & KTRFAC_ROOT) == 0) || caller->pc_ucred->cr_uid == 0) return (1); return (0); } #endif /* KTRACE */ diff --git a/sys/sys/ktr.h b/sys/sys/ktr.h new file mode 100644 index 000000000000..fcafa6e9844a --- /dev/null +++ b/sys/sys/ktr.h @@ -0,0 +1,319 @@ +/*- + * Copyright (c) 1996 Berkeley Software Design, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Berkeley Software Design Inc's name may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from BSDI $Id: ktr.h,v 1.10.2.7 2000/03/16 21:44:42 cp Exp $ + * $FreeBSD$ + */ + +/* + * Wraparound kernel trace buffer support. + */ + +#ifndef _SYS_KTR_H_ +#define _SYS_KTR_H_ + +/* Requires sys/types.h, sys/time.h, machine/atomic.h, and machine/cpufunc.h */ + +#include +#include + +/* + * Trace classes + */ +#define KTR_GEN 0x00000001 /* General (TR) */ +#define KTR_NET 0x00000002 /* Network */ +#define KTR_DEV 0x00000004 /* Device driver */ +#define KTR_LOCK 0x00000008 /* MP locking */ +#define KTR_SMP 0x00000010 /* MP general */ +#define KTR_FS 0x00000020 /* Filesystem */ +#define KTR_PMAP 0x00000040 /* Pmap tracing */ +#define KTR_MALLOC 0x00000080 /* Malloc tracing */ +#define KTR_TRAP 0x00000100 /* Trap processing */ +#define KTR_INTR 0x00000200 /* Interrupt tracing */ +#define KTR_SIG 0x00000400 /* Signal processing */ +#define KTR_CLK 0x00000800 /* hardclock verbose */ +#define KTR_PROC 0x00001000 /* Process scheduling */ +#define KTR_SYSC 0x00002000 /* System call */ +#define KTR_INIT 0x00004000 /* System initialization */ +#define KTR_KGDB 0x00008000 /* Trace kgdb internals */ +#define KTR_IO 0x00010000 /* Upper I/O */ +#define KTR_LOCKMGR 0x00020000 +#define KTR_NFS 0x00040000 /* The obvious */ +#define KTR_VOP 0x00080000 /* The obvious */ +#define KTR_VM 0x00100000 /* The virtual memory system */ +#define KTR_IDLELOOP 0x00200000 /* checks done in the idle process */ + +/* + * Trace classes which can be assigned to particular use at compile time + * These must remain in high 22 as some assembly code counts on it + */ +#define KTR_CT1 0x010000000 +#define KTR_CT2 0x020000000 +#define KTR_CT3 0x040000000 +#define KTR_CT4 0x080000000 +#define KTR_CT5 0x100000000 +#define KTR_CT6 0x200000000 +#define KTR_CT7 0x400000000 +#define KTR_CT8 0x800000000 + +/* Trace classes to compile in */ +#ifndef KTR_COMPILE +#define KTR_COMPILE (KTR_GEN) +#endif + +#ifndef KTR_MASK +#define KTR_MASK (KTR_GEN) +#endif + +#ifndef KTR_CPUMASK +#define KTR_CPUMASK (~0) +#endif + +#ifndef LOCORE + +#include + +struct ktr_entry { + struct timespec ktr_tv; +#ifdef KTR_EXTEND +#ifndef KTRDESCSIZE +#define KTRDESCSIZE 80 +#endif +#ifndef KTRFILENAMESIZE +#define KTRFILENAMESIZE 32 +#endif + char ktr_desc [KTRDESCSIZE]; + char ktr_filename [KTRFILENAMESIZE]; + int ktr_line; + int ktr_cpu; +#else + char *ktr_desc; + u_long ktr_parm1; + u_long ktr_parm2; + u_long ktr_parm3; + u_long ktr_parm4; + u_long ktr_parm5; +#endif +}; + +/* These variables are used by gdb to analyse the output */ +extern int ktr_extend; + +extern int ktr_cpumask; +extern int ktr_mask; +extern int ktr_entries; + +extern volatile int ktr_idx; +extern struct ktr_entry ktr_buf[]; + +#endif /* !LOCORE */ +#ifdef KTR + +#ifndef KTR_ENTRIES +#define KTR_ENTRIES 1024 +#endif + +#ifdef KTR_EXTEND +#ifndef _TR_CPU +#ifdef SMP +#define _TR_CPU cpuid +#else +#define _TR_CPU 0 +#endif +#endif +#ifndef _TR +#define _TR() \ + struct ktr_entry *_ktrptr; \ + int _ktr_newidx, _ktr_saveidx; \ + int _tr_intrsave = save_intr(); \ + disable_intr(); \ + do { \ + _ktr_saveidx = ktr_idx; \ + _ktr_newidx = (ktr_idx + 1) % KTR_ENTRIES; \ + } while (atomic_cmpset_int(&ktr_idx, _ktr_saveidx, _ktr_newidx) == 0); \ + _ktrptr = &ktr_buf[_ktr_saveidx]; \ + restore_intr(_tr_intrsave); \ + nanotime(&_ktrptr->ktr_tv); \ + snprintf (_ktrptr->ktr_filename, KTRFILENAMESIZE, "%s", __FILE__); \ + _ktrptr->ktr_line = __LINE__; \ + _ktrptr->ktr_cpu = _TR_CPU; +#endif +#define CTR0(m, _desc) \ + if (KTR_COMPILE & m) { \ + if ((ktr_mask & (m)) && ((1 << _TR_CPU) & ktr_cpumask)) { \ + _TR() \ + memcpy (_ktrptr->ktr_desc, _desc, KTRDESCSIZE); \ + } \ + } +#define CTR1(m, _desc, _p1) \ + if (KTR_COMPILE & m) { \ + if ((ktr_mask & (m)) && ((1 << _TR_CPU) & ktr_cpumask)) { \ + _TR() \ + snprintf (_ktrptr->ktr_desc, KTRDESCSIZE, _desc, _p1); \ + } \ + } +#define CTR2(m, _desc, _p1, _p2) \ + if (KTR_COMPILE & m) { \ + if ((ktr_mask & (m)) && ((1 << _TR_CPU) & ktr_cpumask)) { \ + _TR() \ + snprintf (_ktrptr->ktr_desc, KTRDESCSIZE, _desc, _p1, _p2); \ + } \ + } +#define CTR3(m, _desc, _p1, _p2, _p3) \ + if (KTR_COMPILE & m) { \ + if ((ktr_mask & (m)) && ((1 << _TR_CPU) & ktr_cpumask)) { \ + _TR() \ + snprintf (_ktrptr->ktr_desc, KTRDESCSIZE, _desc, _p1, _p2, _p3); \ + } \ + } +#define CTR4(m, _desc, _p1, _p2, _p3, _p4) \ + if (KTR_COMPILE & m) { \ + if ((ktr_mask & (m)) && ((1 << _TR_CPU) & ktr_cpumask)) { \ + _TR() \ + snprintf (_ktrptr->ktr_desc, KTRDESCSIZE, _desc, _p1, _p2, _p3, _p4); \ + } \ + } +#define CTR5(m, _desc, _p1, _p2, _p3, _p4, _p5) \ + if (KTR_COMPILE & m) { \ + if ((ktr_mask & (m)) && ((1 << _TR_CPU) & ktr_cpumask)) { \ + _TR() \ + snprintf (_ktrptr->ktr_desc, KTRDESCSIZE, _desc, _p1, _p2, _p3, _p4, _p5); \ + } \ + } + +#else /* not extended */ +#ifndef _TR +#define _TR(_desc) \ + struct ktr_entry *_ktrptr; \ + int _ktr_newidx, _ktr_saveidx; \ + do { \ + _ktr_saveidx = ktr_idx; \ + _ktr_newidx = (ktr_idx + 1) % KTR_ENTRIES; \ + } while (atomic_cmpset_int(&ktr_idx, _ktr_saveidx, _ktr_newidx) == 0); \ + _ktrptr = &ktr_buf[_ktr_saveidx]; \ + nanotime(&_ktrptr->ktr_tv); \ + _ktrptr->ktr_desc = (_desc); +#endif +#define CTR0(m, _desc) \ + if (KTR_COMPILE & m) { \ + if (ktr_mask & (m)) { \ + _TR(_desc) \ + } \ + } +#define CTR1(m, _desc, _p1) \ + if (KTR_COMPILE & m) { \ + if (ktr_mask & (m)) { \ + _TR(_desc) \ + _ktrptr->ktr_parm1 = (u_long)(_p1); \ + } \ + } +#define CTR2(m, _desc, _p1, _p2) \ + if (KTR_COMPILE & m) { \ + if (ktr_mask & (m)) { \ + _TR(_desc) \ + _ktrptr->ktr_parm1 = (u_long)(_p1); \ + _ktrptr->ktr_parm2 = (u_long)(_p2); \ + } \ + } +#define CTR3(m, _desc, _p1, _p2, _p3) \ + if (KTR_COMPILE & m) { \ + if (ktr_mask & (m)) { \ + _TR(_desc) \ + _ktrptr->ktr_parm1 = (u_long)(_p1); \ + _ktrptr->ktr_parm2 = (u_long)(_p2); \ + _ktrptr->ktr_parm3 = (u_long)(_p3); \ + } \ + } +#define CTR4(m, _desc, _p1, _p2, _p3, _p4) \ + if (KTR_COMPILE & m) { \ + if (ktr_mask & (m)) { \ + _TR(_desc) \ + _ktrptr->ktr_parm1 = (u_long)(_p1); \ + _ktrptr->ktr_parm2 = (u_long)(_p2); \ + _ktrptr->ktr_parm3 = (u_long)(_p3); \ + _ktrptr->ktr_parm4 = (u_long)(_p4); \ + } \ + } +#define CTR5(m, _desc, _p1, _p2, _p3, _p4, _p5) \ + if (KTR_COMPILE & m) { \ + if (ktr_mask & (m)) { \ + _TR(_desc) \ + _ktrptr->ktr_parm1 = (u_long)(_p1); \ + _ktrptr->ktr_parm2 = (u_long)(_p2); \ + _ktrptr->ktr_parm3 = (u_long)(_p3); \ + _ktrptr->ktr_parm4 = (u_long)(_p4); \ + _ktrptr->ktr_parm5 = (u_long)(_p5); \ + } \ + } +#endif +#else /* KTR */ +#undef KTR_COMPILE +#define KTR_COMPILE 0 +#define CTR0(m, d) +#define CTR1(m, d, p1) +#define CTR2(m, d, p1, p2) +#define CTR3(m, d, p1, p2, p3) +#define CTR4(m, d, p1, p2, p3, p4) +#define CTR5(m, d, p1, p2, p3, p4, p5) +/* XXX vvvvvvvv ??? */ +#define SEG_ATR(d,s) +#define SEG_ATR_DESC(d,s) +#define ATR(d) +#define CATR(f,d,n) +#define CATRD(f,d,n) +#endif /* KTR */ + +#define TR0(d) CTR0(KTR_GEN, d) +#define TR1(d, p1) CTR1(KTR_GEN, d, p1) +#define TR2(d, p1, p2) CTR2(KTR_GEN, d, p1, p2) +#define TR3(d, p1, p2, p3) CTR3(KTR_GEN, d, p1, p2, p3) +#define TR4(d, p1, p2, p3, p4) CTR4(KTR_GEN, d, p1, p2, p3, p4) +#define TR5(d, p1, p2, p3, p4, p5) CTR5(KTR_GEN, d, p1, p2, p3, p4, p5) + +/* + * Trace initialization events, similar to CTR with KTR_INIT, but + * completely ifdef'ed out if KTR_INIT isn't in KTR_COMPILE (to + * save string space, the compiler doesn't optimize out strings + * for the conditional ones above). + */ +#if (KTR_COMPILE & KTR_INIT) != 0 +#define ITR0(d) CTR0(KTR_INIT, d) +#define ITR1(d, p1) CTR1(KTR_INIT, d, p1) +#define ITR2(d, p1, p2) CTR2(KTR_INIT, d, p1, p2) +#define ITR3(d, p1, p2, p3) CTR3(KTR_INIT, d, p1, p2, p3) +#define ITR4(d, p1, p2, p3, p4) CTR4(KTR_INIT, d, p1, p2, p3, p4) +#define ITR5(d, p1, p2, p3, p4, p5) CTR5(KTR_INIT, d, p1, p2, p3, p4, p5) +#else +#define ITR0(d) +#define ITR1(d, p1) +#define ITR2(d, p1, p2) +#define ITR3(d, p1, p2, p3) +#define ITR4(d, p1, p2, p3, p4) +#define ITR5(d, p1, p2, p3, p4, p5) +#endif + +#endif /* !_SYS_KTR_H_ */ diff --git a/sys/sys/ktrace.h b/sys/sys/ktrace.h index a6a24428b8dd..7c84690e0f2f 100644 --- a/sys/sys/ktrace.h +++ b/sys/sys/ktrace.h @@ -1,178 +1,178 @@ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ktrace.h 8.1 (Berkeley) 6/2/93 * $FreeBSD$ */ #ifndef _SYS_KTRACE_H_ #define _SYS_KTRACE_H_ /* * operations to ktrace system call (KTROP(op)) */ #define KTROP_SET 0 /* set trace points */ #define KTROP_CLEAR 1 /* clear trace points */ #define KTROP_CLEARFILE 2 /* stop all tracing to file */ #define KTROP(o) ((o)&3) /* macro to extract operation */ /* * flags (ORed in with operation) */ #define KTRFLAG_DESCEND 4 /* perform op on all children too */ /* * ktrace record header */ struct ktr_header { int ktr_len; /* length of buf */ short ktr_type; /* trace record type */ pid_t ktr_pid; /* process id */ char ktr_comm[MAXCOMLEN+1]; /* command name */ struct timeval ktr_time; /* timestamp */ - caddr_t ktr_buf; + caddr_t ktr_buffer; }; /* * Test for kernel trace point (MP SAFE) */ #define KTRPOINT(p, type) \ (((p)->p_traceflag & ((1<<(type))|KTRFAC_ACTIVE)) == (1<<(type))) /* * ktrace record types */ /* * KTR_SYSCALL - system call record */ #define KTR_SYSCALL 1 struct ktr_syscall { short ktr_code; /* syscall number */ short ktr_narg; /* number of arguments */ /* * followed by ktr_narg register_t */ register_t ktr_args[1]; }; /* * KTR_SYSRET - return from system call record */ #define KTR_SYSRET 2 struct ktr_sysret { short ktr_code; short ktr_eosys; int ktr_error; register_t ktr_retval; }; /* * KTR_NAMEI - namei record */ #define KTR_NAMEI 3 /* record contains pathname */ /* * KTR_GENIO - trace generic process i/o */ #define KTR_GENIO 4 struct ktr_genio { int ktr_fd; enum uio_rw ktr_rw; /* * followed by data successfully read/written */ }; /* * KTR_PSIG - trace processed signal */ #define KTR_PSIG 5 struct ktr_psig { int signo; sig_t action; int code; sigset_t mask; }; /* * KTR_CSW - trace context switches */ #define KTR_CSW 6 struct ktr_csw { int out; /* 1 if switch out, 0 if switch in */ int user; /* 1 if usermode (ivcsw), 0 if kernel (vcsw) */ }; /* * KTR_USER - data comming from userland */ #define KTR_USER 7 /* * kernel trace points (in p_traceflag) */ #define KTRFAC_MASK 0x00ffffff #define KTRFAC_SYSCALL (1< __BEGIN_DECLS int ktrace __P((const char *, int, int, pid_t)); int utrace __P((const void *, size_t)); __END_DECLS #endif #endif