diff -urP linux-2.2.18/Documentation/Configure.help linux-2.2.18-ltt-0.9.4/Documentation/Configure.help --- linux-2.2.18/Documentation/Configure.help Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/Documentation/Configure.help Mon Mar 19 15:59:23 2001 @@ -13505,6 +13505,43 @@ If you do not have a CompactPCI model CP1400 or CP1500, or another UltraSPARC-IIi-cEngine boardset with digital display, you should say N to this option. + +Kernel events tracing support +CONFIG_TRACE + It is possible for the kernel to log important events to a tracing + driver. Doing so, enables the use of the generated traces in order + to reconstruct the dynamic behavior of the kernel, and hence the + whole system. + + The tracing process contains 4 parts : + 1) The logging of events by key parts of the kernel. + 2) The trace driver that keeps the events in a data buffer. + 3) A trace daemon that opens the trace driver and is notified + every time there is a certain quantity of data to read + from the trace driver (using SIG_IO). + 4) A trace event data decoder that reads the accumulated data + and formats it in a human-readable format. + + If you say Y or M here, the first part of the tracing process will + always take place. That is, critical parts of the kernel will call + upon the kernel tracing function. The data generated doesn't go + any further until a trace driver registers himself as such with the + kernel. Therefore, if you answer Y, then the driver will be part of + the kernel and the events will always proceed onto the driver and + if you say M, then the events will only proceed onto the driver when + it's module is loaded. Note that event's aren't logged in the driver + until the profiling daemon opens the device, configures it and + issues the "start" command through ioctl(). + + The impact of a fully functionnal system (kernel event logging + + driver event copying + active trace daemon) is of 2.5% for core events. + This means that for a task that took 100 seconds on a normal system, it + will take 102.5 seconds on a traced system. This is very low compared + to other profiling or tracing methods. + + For more information on kernel tracing, the trace daemon or the event + decoder, please check the following address : + http://www.opersys.com/LTT # # A couple of things I keep forgetting: diff -urP linux-2.2.18/Makefile linux-2.2.18-ltt-0.9.4/Makefile --- linux-2.2.18/Makefile Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/Makefile Mon Mar 19 15:59:23 2001 @@ -218,6 +218,10 @@ DRIVERS := $(DRIVERS) drivers/telephony/telephony.a endif +ifeq ($(CONFIG_TRACE),y) +DRIVERS := $(DRIVERS) drivers/trace/tracer.a +endif + include arch/$(ARCH)/Makefile .S.s: diff -urP linux-2.2.18/arch/i386/config.in linux-2.2.18-ltt-0.9.4/arch/i386/config.in --- linux-2.2.18/arch/i386/config.in Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/arch/i386/config.in Mon Mar 19 15:59:23 2001 @@ -206,6 +206,11 @@ endmenu mainmenu_option next_comment +comment 'Kernel tracing' +tristate 'Kernel events tracing support' CONFIG_TRACE +endmenu + +mainmenu_option next_comment comment 'Kernel hacking' #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC diff -urP linux-2.2.18/arch/i386/kernel/entry.S linux-2.2.18-ltt-0.9.4/arch/i386/kernel/entry.S --- linux-2.2.18/arch/i386/kernel/entry.S Mon Sep 4 13:39:16 2000 +++ linux-2.2.18-ltt-0.9.4/arch/i386/kernel/entry.S Mon Mar 19 15:59:23 2001 @@ -176,8 +176,22 @@ jae badsys testb $0x20,flags(%ebx) # PF_TRACESYS jne tracesys + +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) + movl %esp, %eax # copy the stack pointer + pushl %eax # pass the stack pointer copy + call SYMBOL_NAME(trace_real_syscall_entry) + addl $4,%esp # return stack to state before pass + movl ORIG_EAX(%esp),%eax # restore eax to it's original content +#endif + call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return value + +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) + call SYMBOL_NAME(trace_real_syscall_exit) +#endif + ALIGN .globl ret_from_sys_call .globl ret_from_intr diff -urP linux-2.2.18/arch/i386/kernel/irq.c linux-2.2.18-ltt-0.9.4/arch/i386/kernel/irq.c --- linux-2.2.18/arch/i386/kernel/irq.c Wed Jun 7 17:26:42 2000 +++ linux-2.2.18-ltt-0.9.4/arch/i386/kernel/irq.c Mon Mar 19 15:59:23 2001 @@ -31,6 +31,8 @@ #include #include +#include + #include #include #include @@ -235,6 +237,8 @@ struct irqaction * action; irq_desc_t *desc = irq_desc + irq; + TRACE_IRQ_ENTRY(irq, !(user_mode(regs))); + spin_lock(&irq_controller_lock); { unsigned int status; @@ -263,6 +267,8 @@ enable_8259A_irq(irq); } spin_unlock(&irq_controller_lock); + + TRACE_EVENT(TRACE_EV_IRQ_EXIT, NULL); } /* diff -urP linux-2.2.18/arch/i386/kernel/process.c linux-2.2.18-ltt-0.9.4/arch/i386/kernel/process.c --- linux-2.2.18/arch/i386/kernel/process.c Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/arch/i386/kernel/process.c Mon Mar 19 15:59:23 2001 @@ -33,6 +33,8 @@ #include #include +#include + #include #include #include @@ -516,6 +518,10 @@ "r" (arg), "r" (fn), "b" (flags | CLONE_VM) : "memory"); +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) + if (retval > 0) + TRACE_PROCESS(TRACE_EV_PROCESS_KTHREAD, retval, (int) fn); +#endif return retval; } diff -urP linux-2.2.18/arch/i386/kernel/sys_i386.c linux-2.2.18-ltt-0.9.4/arch/i386/kernel/sys_i386.c --- linux-2.2.18/arch/i386/kernel/sys_i386.c Thu Dec 17 19:27:35 1998 +++ linux-2.2.18-ltt-0.9.4/arch/i386/kernel/sys_i386.c Mon Mar 19 15:59:23 2001 @@ -19,6 +19,8 @@ #include #include +#include + #include #include @@ -115,6 +117,8 @@ version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; + + TRACE_IPC(TRACE_EV_IPC_CALL, call, first); if (call <= SEMCTL) switch (call) { diff -urP linux-2.2.18/arch/i386/kernel/traps.c linux-2.2.18-ltt-0.9.4/arch/i386/kernel/traps.c --- linux-2.2.18/arch/i386/kernel/traps.c Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/arch/i386/kernel/traps.c Mon Mar 19 15:59:23 2001 @@ -21,6 +21,8 @@ #include #include +#include + #ifdef CONFIG_MCA #include #include @@ -67,8 +69,10 @@ { \ tsk->tss.error_code = error_code; \ tsk->tss.trap_no = trapnr; \ + TRACE_TRAP_ENTRY(trapnr, regs->eip);\ force_sig(signr, tsk); \ die_if_no_fixup(str,regs,error_code); \ + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); \ } #define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \ @@ -82,8 +86,10 @@ } \ tsk->tss.error_code = error_code; \ tsk->tss.trap_no = trapnr; \ + TRACE_TRAP_ENTRY(trapnr, regs->eip);\ force_sig(signr, tsk); \ die_if_kernel(str,regs,error_code); \ + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); \ out: \ unlock_kernel(); \ } @@ -202,6 +208,82 @@ printk("\n"); } +/* Trace related code */ +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) +asmlinkage void trace_real_syscall_entry(struct pt_regs * regs) +{ + int use_depth; + int use_bounds; + int depth = 0; + int seek_depth; + unsigned long lower_bound; + unsigned long upper_bound; + unsigned long addr; + unsigned long* stack; + trace_syscall_entry trace_syscall_event; + + /* Set the syscall ID */ + trace_syscall_event.syscall_id = (uint8_t) regs->orig_eax; + + /* Set the address in any case */ + trace_syscall_event.address = regs->eip; + + /* Are we in the kernel (This is a kernel thread)? */ + if(!(regs->xcs & 3)) + /* Don't go digining anywhere */ + goto trace_syscall_end; + + /* Get the trace configuration */ + if(trace_get_config(&use_depth, + &use_bounds, + &seek_depth, + (void*)&lower_bound, + (void*)&upper_bound) < 0) + goto trace_syscall_end; + + /* Do we have to search for an eip address range */ + if((use_depth == 1) || (use_bounds == 1)) + { + /* Start at the top of the stack (bottom address since stacks grow downward) */ + stack = (unsigned long*) regs->esp; + + /* Keep on going until we reach the end of the process' stack limit (wherever it may be) */ + while(!get_user(addr, stack)) + { + /* Does this LOOK LIKE an address in the program */ + if((addr > current->mm->start_code) + &&(addr < current->mm->end_code)) + { + /* Does this address fit the description */ + if(((use_depth == 1) && (depth == seek_depth)) + ||((use_bounds == 1) && (addr > lower_bound) && (addr < upper_bound))) + { + /* Set the address */ + trace_syscall_event.address = addr; + + /* We're done */ + goto trace_syscall_end; + } + else + /* We're one depth more */ + depth++; + } + /* Go on to the next address */ + stack++; + } + } + +trace_syscall_end: + /* Trace the event */ + trace_event(TRACE_EV_SYSCALL_ENTRY, &trace_syscall_event); +} + +asmlinkage void trace_real_syscall_exit(void) +{ + trace_event(TRACE_EV_SYSCALL_EXIT, NULL); +} +#endif /* (CONFIG_TRACE || CONFIG_TRACE_MODULE) */ + spinlock_t die_lock; void die(const char * str, struct pt_regs * regs, long err) @@ -273,12 +355,16 @@ current->tss.error_code = error_code; current->tss.trap_no = 13; + TRACE_TRAP_ENTRY(13, regs->eip); force_sig(SIGSEGV, current); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; gp_in_vm86: lock_kernel(); + TRACE_TRAP_ENTRY(13, regs->eip); handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); unlock_kernel(); return; @@ -343,6 +429,8 @@ io_check_error(reason, regs); if (!(reason & 0xc0)) unknown_nmi_error(reason, regs); + TRACE_TRAP_ENTRY(2, regs->eip); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); } /* @@ -400,12 +488,16 @@ tsk->tss.trap_no = 1; tsk->tss.error_code = error_code; tsk->tss.debugreg[DR_STATUS] = condition; + TRACE_TRAP_ENTRY(1, regs->eip); force_sig(SIGTRAP, tsk); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; debug_vm86: lock_kernel(); + TRACE_TRAP_ENTRY(1, regs->eip); handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); unlock_kernel(); return; @@ -442,17 +534,21 @@ asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code) { + TRACE_TRAP_ENTRY(16, regs->eip); ignore_irq13 = 1; math_error(); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); } asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs, long error_code) { + TRACE_TRAP_ENTRY(16, regs->eip); #if 0 /* No need to warn about this any longer. */ printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); #endif + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); } /* @@ -485,8 +581,10 @@ lock_kernel(); printk("math-emulation not enabled and no coprocessor found.\n"); printk("killing %s.\n",current->comm); + TRACE_TRAP_ENTRY(7, 0); force_sig(SIGFPE,current); schedule(); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); unlock_kernel(); } diff -urP linux-2.2.18/arch/i386/mm/fault.c linux-2.2.18-ltt-0.9.4/arch/i386/mm/fault.c --- linux-2.2.18/arch/i386/mm/fault.c Wed May 3 20:16:31 2000 +++ linux-2.2.18-ltt-0.9.4/arch/i386/mm/fault.c Mon Mar 19 15:59:23 2001 @@ -17,6 +17,8 @@ #include #include +#include + #include #include #include @@ -124,6 +126,8 @@ tsk = current; mm = tsk->mm; + TRACE_TRAP_ENTRY(14, regs->eip); + /* * If we're in an interrupt or have no user * context, we must not take the fault.. @@ -200,6 +204,7 @@ tsk->tss.screen_bitmap |= 1 << bit; } up(&mm->mmap_sem); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; /* @@ -215,6 +220,7 @@ tsk->tss.error_code = error_code; tsk->tss.trap_no = 14; force_sig(SIGSEGV, tsk); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; } @@ -228,6 +234,7 @@ if (nr == 6) { do_invalid_op(regs, 0); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; } } @@ -236,6 +243,7 @@ /* Are we prepared to handle this kernel fault? */ if ((fixup = search_exception_table(regs->eip)) != 0) { regs->eip = fixup; + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; } @@ -330,4 +338,6 @@ /* Kernel mode? Handle exceptions or die */ if (!(error_code & 4)) goto no_context; + + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); } diff -urP linux-2.2.18/arch/ppc/config.in linux-2.2.18-ltt-0.9.4/arch/ppc/config.in --- linux-2.2.18/arch/ppc/config.in Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/arch/ppc/config.in Mon Mar 19 15:59:23 2001 @@ -208,6 +208,11 @@ source fs/Config.in mainmenu_option next_comment +comment 'Kernel tracing' +tristate 'Kernel events tracing support' CONFIG_TRACE +endmenu + +mainmenu_option next_comment comment 'Kernel hacking' bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ diff -urP linux-2.2.18/arch/ppc/kernel/head.S linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/head.S --- linux-2.2.18/arch/ppc/kernel/head.S Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/head.S Mon Mar 19 15:59:23 2001 @@ -2091,6 +2091,32 @@ SYNC rfi /* enable MMU and jump to start_kernel */ +/* LTT stuff */ +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) +#define TRACE_REAL_ASM_SYSCALL_ENTRY \ + addi r3,r1,STACK_FRAME_OVERHEAD; /* Put pointer to registers into r3 */ \ + mflr r29; /* Save LR */ \ + bl trace_real_syscall_entry; /* Call real trace function */ \ + mtlr r29; /* Restore LR */ \ + lwz r0,GPR0(r1); /* Restore original registers */ \ + lwz r3,GPR3(r1); \ + lwz r4,GPR4(r1); \ + lwz r5,GPR5(r1); \ + lwz r6,GPR6(r1); \ + lwz r7,GPR7(r1); \ + lwz r8,GPR8(r1); +#define TRACE_REAL_ASM_SYSCALL_EXIT \ + bl trace_real_syscall_exit; /* Call real trace function */ \ + lwz r0,GPR0(r1); /* Restore original registers */ \ + lwz r3,RESULT(r1); \ + lwz r4,GPR4(r1); \ + lwz r5,GPR5(r1); \ + lwz r6,GPR6(r1); \ + lwz r7,GPR7(r1); \ + lwz r8,GPR8(r1); \ + addi r9,r1,STACK_FRAME_OVERHEAD; +#endif + /* * Handle a system call. */ @@ -2141,11 +2167,17 @@ cmpi 0,r10,0 beq- 66f mtlr r10 +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) + TRACE_REAL_ASM_SYSCALL_ENTRY ; +#endif addi r9,r1,STACK_FRAME_OVERHEAD blrl /* Call handler */ .globl syscall_ret_1 syscall_ret_1: 20: stw r3,RESULT(r1) /* Save result */ +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) + TRACE_REAL_ASM_SYSCALL_EXIT ; +#endif #ifdef SHOW_SYSCALLS #ifdef SHOW_SYSCALLS_TASK cmp 0,r2,r31 @@ -2203,11 +2235,17 @@ cmpi 0,r10,0 beq- 66f mtlr r10 +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) + TRACE_REAL_ASM_SYSCALL_ENTRY ; +#endif addi r9,r1,STACK_FRAME_OVERHEAD blrl /* Call handler */ .globl syscall_ret_2 syscall_ret_2: stw r3,RESULT(r1) /* Save result */ +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) + TRACE_REAL_ASM_SYSCALL_EXIT ; +#endif stw r3,GPR0(r1) /* temporary gross hack to make strace work */ li r10,-_LAST_ERRNO cmpl 0,r3,r10 diff -urP linux-2.2.18/arch/ppc/kernel/irq.c linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/irq.c --- linux-2.2.18/arch/ppc/kernel/irq.c Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/irq.c Mon Mar 19 15:59:23 2001 @@ -44,6 +44,8 @@ #include #include +#include + #include #include #include @@ -261,6 +263,8 @@ int status; struct irqaction *action; int cpu = smp_processor_id(); + + TRACE_IRQ_ENTRY(irq, !(user_mode(regs))); mask_and_ack_irq(irq); status = 0; @@ -280,6 +284,8 @@ ppc_spurious_interrupts++; disable_irq( irq ); } + + TRACE_EVENT(TRACE_EV_IRQ_EXIT, NULL); } asmlinkage void do_IRQ(struct pt_regs *regs, int isfake) diff -urP linux-2.2.18/arch/ppc/kernel/misc.S linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/misc.S --- linux-2.2.18/arch/ppc/kernel/misc.S Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/misc.S Mon Mar 19 15:59:23 2001 @@ -812,13 +812,21 @@ * Create a kernel thread * kernel_thread(fn, arg, flags) */ +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) +_GLOBAL(original_kernel_thread) +#else _GLOBAL(kernel_thread) +#endif /* (CONFIG_TRACE || CONFIG_TRACE_MODULE) */ mr r6,r3 /* function */ ori r3,r5,CLONE_VM /* flags */ li r0,__NR_clone sc cmpi 0,r3,0 /* parent or child? */ +#if 0 /* (CONFIG_TRACE || CONFIG_TRACE_MODULE) */ + bne trace_kernel_thread_create +#else bnelr /* return if parent */ +#endif li r0,0 /* clear out p->tss.regs */ stw r0,TSS+PT_REGS(r2) /* since we don't have user ctx */ mtlr r6 /* fn addr in lr */ @@ -827,6 +835,15 @@ li r0,__NR_exit /* exit after child exits */ li r3,0 sc + +#if 0 +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) +trace_kernel_thread_create: + li r0,real_trace_kernel_thread_create + sc /* Call the real tracing function */ + blr /* Return to the parent */ +#endif +#endif #define SYSCALL(name) \ _GLOBAL(name) \ diff -urP linux-2.2.18/arch/ppc/kernel/process.c linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/process.c --- linux-2.2.18/arch/ppc/kernel/process.c Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/process.c Mon Mar 19 15:59:23 2001 @@ -33,6 +33,8 @@ #include #include +#include + #include #include #include @@ -309,6 +311,19 @@ } printk("\n"); } + +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) +long original_kernel_thread(int (*fn) (void *), void* arg, unsigned long flags); +long kernel_thread(int (*fn) (void *), void* arg, unsigned long flags) +{ + long retval; + + retval = original_kernel_thread(fn, arg, flags); + if (retval > 0) + TRACE_PROCESS(TRACE_EV_PROCESS_KTHREAD, retval, (int) fn); + return retval; +} +#endif /* (CONFIG_TRACE || CONFIG_TRACE_MODULE) */ void exit_thread(void) { diff -urP linux-2.2.18/arch/ppc/kernel/syscalls.c linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/syscalls.c --- linux-2.2.18/arch/ppc/kernel/syscalls.c Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/syscalls.c Mon Mar 19 15:59:23 2001 @@ -34,6 +34,8 @@ #include #include +#include + #include #include @@ -85,6 +87,8 @@ lock_kernel(); version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; + + TRACE_IPC(TRACE_EV_IPC_CALL, call, first); ret = -EINVAL; switch (call) { diff -urP linux-2.2.18/arch/ppc/kernel/time.c linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/time.c --- linux-2.2.18/arch/ppc/kernel/time.c Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/time.c Mon Mar 19 15:59:23 2001 @@ -36,6 +36,8 @@ #include #include +#include + #include #include #include @@ -72,6 +74,8 @@ int dval, d; unsigned long cpu = smp_processor_id(); + TRACE_TRAP_ENTRY(regs->trap, instruction_pointer(regs)); + hardirq_enter(cpu); #ifdef __SMP__ { @@ -145,6 +149,8 @@ #endif hardirq_exit(cpu); + + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); } /* diff -urP linux-2.2.18/arch/ppc/kernel/traps.c linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/traps.c --- linux-2.2.18/arch/ppc/kernel/traps.c Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/arch/ppc/kernel/traps.c Mon Mar 19 15:59:23 2001 @@ -30,6 +30,8 @@ #include #include +#include + #include #include #include @@ -81,7 +83,9 @@ print_backtrace((unsigned long *)regs->gpr[1]); panic("Exception in kernel pc %lx signal %d",regs->nip,signr); } + TRACE_TRAP_ENTRY(regs->trap, instruction_pointer(regs)); force_sig(signr, current); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); } void @@ -266,6 +270,89 @@ print_backtrace((unsigned long *)regs->gpr[1]); panic("kernel stack overflow"); } + +/* Trace related code */ +#if (CONFIG_TRACE || CONFIG_TRACE_MODULE) +asmlinkage void trace_real_syscall_entry(struct pt_regs * regs) +{ + int use_depth; + int use_bounds; + int depth = 0; + int seek_depth; + unsigned long lower_bound; + unsigned long upper_bound; + unsigned long addr; + unsigned long* stack; + trace_syscall_entry trace_syscall_event; + + /* Set the syscall ID */ + trace_syscall_event.syscall_id = (uint8_t) regs->gpr[0]; + + /* Set the address in any case */ + trace_syscall_event.address = instruction_pointer(regs); + + /* Are we in the kernel (This is a kernel thread)? */ + if(!user_mode(regs)) + /* Don't go digining anywhere */ + goto trace_syscall_end; + + /* Get the trace configuration */ + if(trace_get_config(&use_depth, + &use_bounds, + &seek_depth, + (void*)&lower_bound, + (void*)&upper_bound) < 0) + goto trace_syscall_end; + + /* Do we have to search for an eip address range */ + if((use_depth == 1) || (use_bounds == 1)) + { + /* Start at the top of the stack (bottom address since stacks grow downward) */ + stack = (unsigned long*) regs->gpr[1]; + + /* Skip over first stack frame as the return address isn't valid */ + if(get_user(addr, stack)) + goto trace_syscall_end; + stack = (unsigned long*) addr; + + /* Keep on going until we reach the end of the process' stack limit (wherever it may be) */ + while(!get_user(addr, stack + 1)) /* "stack + 1", since this is where the IP is */ + { + /* Does this LOOK LIKE an address in the program */ + if((addr > current->mm->start_code) + &&(addr < current->mm->end_code)) + { + /* Does this address fit the description */ + if(((use_depth == 1) && (depth == seek_depth)) + ||((use_bounds == 1) && (addr > lower_bound) && (addr < upper_bound))) + { + /* Set the address */ + trace_syscall_event.address = addr; + + /* We're done */ + goto trace_syscall_end; + } + else + /* We're one depth more */ + depth++; + } + /* Go on to the next address */ + if(get_user(addr, stack)) + goto trace_syscall_end; + stack = (unsigned long*) addr; + } + } + +trace_syscall_end: + /* Trace the event */ + trace_event(TRACE_EV_SYSCALL_ENTRY, &trace_syscall_event); +} + +asmlinkage void trace_real_syscall_exit(void) +{ + trace_event(TRACE_EV_SYSCALL_EXIT, NULL); +} +#endif /* (CONFIG_TRACE || CONFIG_TRACE_MODULE) */ void trace_syscall(struct pt_regs *regs) diff -urP linux-2.2.18/arch/ppc/mm/fault.c linux-2.2.18-ltt-0.9.4/arch/ppc/mm/fault.c --- linux-2.2.18/arch/ppc/mm/fault.c Mon Sep 4 13:39:16 2000 +++ linux-2.2.18-ltt-0.9.4/arch/ppc/mm/fault.c Mon Mar 19 15:59:23 2001 @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -75,19 +77,26 @@ if (regs->trap == 0x400) error_code &= 0x48200000; + TRACE_TRAP_ENTRY(regs->trap, instruction_pointer(regs)); + #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_fault_handler && regs->trap == 0x300) { debugger_fault_handler(regs); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; } if (error_code & 0x00400000) { /* DABR match */ - if (debugger_dabr_match(regs)) + if (debugger_dabr_match(regs)) { + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; + } } #endif + if (in_interrupt() || mm == &init_mm) { bad_page_fault(regs, address, error_code); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; } @@ -145,12 +154,14 @@ * -- Cort */ pte_misses++; + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; bad_area: up(&mm->mmap_sem); pte_errors++; bad_page_fault(regs, address, error_code); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; /* @@ -169,6 +180,7 @@ do_exit(SIGKILL); } bad_page_fault(regs, address, error_code); + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); return; do_sigbus: @@ -183,6 +195,8 @@ /* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) bad_page_fault(regs, address, error_code); + + TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); } void diff -urP linux-2.2.18/drivers/Makefile linux-2.2.18-ltt-0.9.4/drivers/Makefile --- linux-2.2.18/drivers/Makefile Sun Dec 10 19:49:41 2000 +++ linux-2.2.18-ltt-0.9.4/drivers/Makefile Mon Mar 19 15:59:23 2001 @@ -62,6 +62,16 @@ MOD_SUB_DIRS += sgi endif +# Is the trace module enabled +ifeq ($(CONFIG_TRACE),y) +SUB_DIRS += trace +ALL_SUB_DIRS += trace +else + ifeq ($(CONFIG_TRACE),m) + MOD_SUB_DIRS += trace + endif +endif + # If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel, # but some of the low-level things may also be modules. ifeq ($(CONFIG_SCSI),y) diff -urP linux-2.2.18/drivers/trace/Makefile linux-2.2.18-ltt-0.9.4/drivers/trace/Makefile --- linux-2.2.18/drivers/trace/Makefile Wed Dec 31 19:00:00 1969 +++ linux-2.2.18-ltt-0.9.4/drivers/trace/Makefile Mon Mar 19 15:59:23 2001 @@ -0,0 +1,30 @@ +# +# Makefile for the kernel tracing drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +L_TARGET := +M_OBJS := +L_OBJS := + +# Is it loaded as a module or as part of the kernel +ifeq ($(CONFIG_TRACE),y) +L_OBJS += tracer.o +L_TARGET += tracer.a +else + ifeq ($(CONFIG_TRACE),m) + M_OBJS += tracer.o + endif +endif + +include $(TOPDIR)/Rules.make diff -urP linux-2.2.18/drivers/trace/tracer.c linux-2.2.18-ltt-0.9.4/drivers/trace/tracer.c --- linux-2.2.18/drivers/trace/tracer.c Wed Dec 31 19:00:00 1969 +++ linux-2.2.18-ltt-0.9.4/drivers/trace/tracer.c Mon Mar 19 15:59:23 2001 @@ -0,0 +1,1206 @@ +/***************************************************************** + * File : tracer.c + * Description : + * Contains the code for the kernel tracing driver (tracer + * for short). + * Author : + * Karim Yaghmour + * Date : + * 15/11/00, Finally fixed memory allocation and remapping + * method. Now using BTTV-driver-inspired code. + * 13/03/00, Modified tracer so that the daemon mmaps the + * tracer's buffers in it's address space rather + * than use "read". + * 26/01/00, Added support for standardized buffer sizes and + * extensibility of events. + * 01/10/99, Modified tracer in order to used double-buffering. + * 28/09/99, Adding tracer configuration support. + * 09/09/99, Chaging the format of an event record in order to + * reduce the size of the traces. + * 04/03/99, Initial typing. + * Note : + * The sizes of the variables used to store the details of an + * event are planned for a system who gets at least one clock + * tick every 10milli-seconds. There has to be at least one + * event every 2^32-1 microseconds, otherwise the size of the + * variable holding the time doesn't work anymore. + *****************************************************************/ + +/* Module and initialization stuff */ +#include +#include + +/* Necessary includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Local defintions */ +#include "tracer.h" + +/* Local variables */ +/* Driver */ +static int sMajorNumber; /* Major number of the tracer */ +static int sOpenCount; /* Number of times device is open */ +/* Locking */ +static int sTracLock; /* Tracer lock used to lock primary buffer */ +static spinlock_t sSpinLock; /* Spinlock in order to lock kernel */ +/* Daemon */ +static int sSignalSent; /* A signal has been sent to the daemon */ +static struct task_struct* sDaemonTaskStruct; /* Task structure of the tracer daemon */ +/* Tracer configuration */ +static int sTracerStarted; /* Is the tracer started */ +static trace_event_mask sTracedEvents; /* Bit-field of events being traced */ +static trace_event_mask sLogEventDetailsMask; /* Log the details of the events mask */ +static int sLogCPUID; /* Log the CPUID associated with each event */ +static int sUseSyscallEIPBounds; /* Use adress bounds to fetch the EIP where call is made */ +static int sLowerEIPBoundSet; /* The lower bound EIP has been set */ +static int sUpperEIPBoundSet; /* The upper bound EIP has been set */ +static void* sLowerEIPBound; /* The lower bound EIP */ +static void* sUpperEIPBound; /* The upper bound EIP */ +static int sTracingPID; /* Tracing only the events for one pid */ +static int sTracingPGRP; /* Tracing only the events for one process group */ +static int sTracingGID; /* Tracing only the events for one gid */ +static int sTracingUID; /* Tracing only the events for one uid */ +static pid_t sTracedPID; /* PID being traced */ +static pid_t sTracedPGRP; /* Process group being traced */ +static gid_t sTracedGID; /* GID being traced */ +static uid_t sTracedUID; /* UID being traced */ +static int sSyscallEIPDepthSet; /* The call depth at which to fetch EIP has been set */ +static int sSyscallEIPDepth; /* The call depth at which to fetch the EIP */ +/* Event data buffers */ +static int sBufReadComplete; /* Number of buffers completely filled */ +static int sSizeReadIncomplete; /* Quantity of data read from incomplete buffers */ +static int sEventsLost; /* Number of events lost because of lack of buffer space */ +static uint32_t sBufSize; /* Buffer sizes */ +static uint32_t sAllocSize; /* Size of buffers allocated */ +static uint32_t sBufferID; /* Unique buffer ID */ +static char* sTracBuf = NULL; /* Trace buffer */ +static char* sWritBuf = NULL; /* Buffer used for writting */ +static char* sReadBuf = NULL; /* Buffer used for reading */ +static char* sWritBufEnd; /* End of write buffer */ +static char* sReadBufEnd; /* End of read buffer */ +static char* sWritPos; /* Current position for writting */ +static char* sReadLimit; /* Limit at which read should stop */ +static char* sWritLimit; /* Limit at which write should stop */ +/* Time */ +static struct timeval sBufferStartTime; /* The time at which the buffer was started */ + +/* The size of the structures used to describe the events */ +static int sEventStructSize[TRACE_EV_MAX + 1] = +{ + sizeof(trace_start) /* TRACE_START */, + sizeof(trace_syscall_entry) /* TRACE_SYSCALL_ENTRY */, + 0 /* TRACE_SYSCALL_EXIT */, + sizeof(trace_trap_entry) /* TRACE_TRAP_ENTRY */, + 0 /* TRACE_TRAP_EXIT */, + sizeof(trace_irq_entry) /* TRACE_IRQ_ENTRY */, + 0 /* TRACE_IRQ_EXIT */, + sizeof(trace_schedchange) /* TRACE_SCHEDCHANGE */, + 0 /* TRACE_KERNEL_TIMER */, + sizeof(trace_soft_irq) /* TRACE_SOFT_IRQ */, + sizeof(trace_process) /* TRACE_PROCESS */, + sizeof(trace_file_system) /* TRACE_FILE_SYSTEM */, + sizeof(trace_timer) /* TRACE_TIMER */, + sizeof(trace_memory) /* TRACE_MEMORY */, + sizeof(trace_socket) /* TRACE_SOCKET */, + sizeof(trace_ipc) /* TRACE_IPC */, + sizeof(trace_network) /* TRACE_NETWORK */, + sizeof(trace_buffer_start) /* TRACE_BUFFER_START */, + 0 /* TRACE_BUFFER_END */, + sizeof(trace_new_event) /* TRACE_NEW_EVENT */, + sizeof(trace_custom) /* TRACE_CUSTOM */ +}; + +/* The file operations available for the tracer */ +static struct file_operations sTracerFileOps = +{ + NULL /* llseek */, + NULL /* read */, + NULL /* write */, + NULL /* readdir */, + NULL /* poll */, + &tracer_ioctl /* ioctl */, + &tracer_mmap /* mmap */, + &tracer_open /* open */, + NULL /* flush */, + &tracer_release /* release */, + &tracer_fsync /* fsync */, + NULL /* fasync */, + NULL /* check_media_change */, + NULL /* revalidate */, + NULL /* lock */ +}; + +/************************************************************************************************************/ +/************************************** Code inspired from BTTV driver **************************************/ +/************************************************************************************************************/ +#define FIX_SIZE(x) (((x) - 1) & PAGE_MASK) + PAGE_SIZE /* This inspired by rtai/shmem */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) + ret = (pte_page(pte)|(adr&(PAGE_SIZE-1))); + } + } + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + return ret; +} + +static void * rvmalloc(unsigned long size) +{ + void * mem; + unsigned long adr, page; + + mem=vmalloc(size); + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_reserve(MAP_NR(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, unsigned long size) +{ + unsigned long adr, page; + + if (mem) + { + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_unreserve(MAP_NR(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + +static int tracer_mmap_region(const char *adr, const char *start_pos, unsigned long size) +{ + unsigned long start=(unsigned long) adr; + unsigned long page,pos; + + pos=(unsigned long) start_pos; + while (size > 0) + { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start+=PAGE_SIZE; + pos+=PAGE_SIZE; + size-=PAGE_SIZE; + } + return 0; +} +/************************************************************************************************************/ +/************************************************************************************************************/ +/************************************************************************************************************/ + + +/************************************************************** + * Macro : tracer_write_to_buffer() + * Description : + * Writes data to the destination buffer and updates the + * begining the buffer write position. + **************************************************************/ +#define tracer_write_to_buffer(DEST, SRC, SIZE) \ +do\ +{\ + memcpy(DEST, SRC, SIZE);\ + DEST += SIZE;\ +} while(0); + +/************************************************************** + * Function : trace() + * Description : Tracing function per se. + * Parameters : + * pmEventID, ID of event as defined in linux/trace.h + * pmEventStruct, struct describing the event + * Return values : + * 0, if everything went OK (event got registered) + * -ENODEV, no tracing daemon opened the driver. + * -ENOMEM, no more memory to store events. + * -EBUSY, tracer not started yet. + * Note : + * The kernel has to be locked here because trace() could + * be called from an interrupt handling routine and from + * a process service routine. + **************************************************************/ +int trace(uint8_t pmEventID, + void* pmEventStruct) +{ + int lVarDataLen = 0; /* Length of variable length data to be copied, if any */ + void* lVarDataBeg = NULL; /* Begining of variable length data to be copied */ + int lSendSignal = FALSE; /* Should the daemon be summoned */ + uint8_t lDataSize; /* Size of tracing data */ + uint8_t lCPUID; /* CPUID of currently runing process */ + struct siginfo lSigInfo; /* Signal information */ + struct timeval lTime; /* Event time */ + unsigned long int lFlags; /* CPU flags for lock */ + trace_time_delta lTimeDelta; /* The time elapsed between now and the last event */ + + /* Is there a tracing daemon */ + if(sDaemonTaskStruct == NULL) + return -ENODEV; + + /* Do we trace the event */ + if((sTracerStarted == TRUE) || (pmEventID == TRACE_EV_START) || (pmEventID == TRACE_EV_BUFFER_START)) + goto TraceEvent; + + /* We can't continue */ + return -EBUSY; + +TraceEvent: + + /* Are we monitoring this event */ + if(!test_bit(pmEventID, &sTracedEvents)) + return 0; + + /* Always let the start event pass, whatever the IDs */ + if((pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START)) + { + /* Are we monitoring a particular process */ + if((sTracingPID == TRUE) && (current->pid != sTracedPID)) + return 0; + + /* Are we monitoring a particular process group */ + if((sTracingPGRP == TRUE) && (current->pgrp != sTracedPGRP)) + return 0; + + /* Are we monitoring the processes of a given group of users */ + if((sTracingGID == TRUE) && (current->egid != sTracedGID)) + return 0; + + /* Are we monitoring the processes of a given user */ + if((sTracingUID == TRUE) && (current->euid != sTracedUID)) + return 0; + } + + /* Compute size of tracing data */ + lDataSize = sizeof(pmEventID) + sizeof(lTimeDelta) + sizeof(lDataSize); + + /* Do we log the event details */ + if(test_bit(pmEventID, &sLogEventDetailsMask)) + { + /* Update the size of the data entry */ + lDataSize += sEventStructSize[pmEventID]; + + /* Some events have variable length */ + switch(pmEventID) + { + /* Is there a file name in this */ + case TRACE_EV_FILE_SYSTEM: + if((((trace_file_system*) pmEventStruct)->event_sub_id == TRACE_EV_FILE_SYSTEM_EXEC) + || (((trace_file_system*) pmEventStruct)->event_sub_id == TRACE_EV_FILE_SYSTEM_OPEN)) + { + /* Remember the string's beging and update size variables */ + lVarDataBeg = ((trace_file_system*) pmEventStruct)->file_name; + lVarDataLen = ((trace_file_system*) pmEventStruct)->event_data2 + 1; + lDataSize += lVarDataLen; + } + break; + + /* Declaration of a new event */ + case TRACE_EV_NEW_EVENT: + lVarDataBeg = ((trace_new_event*) pmEventStruct)->data_description; + lVarDataLen = ((trace_new_event*) pmEventStruct)->desc_size; + lDataSize += lVarDataLen; + break; + + /* Logging of a custom event */ + case TRACE_EV_CUSTOM: + lVarDataBeg = ((trace_custom*) pmEventStruct)->data; + lVarDataLen = ((trace_custom*) pmEventStruct)->data_size; + lDataSize += lVarDataLen; + break; + } + } + + /* Do we record the CPUID */ + if((sLogCPUID == TRUE) && (pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START)) + { + /* Remember the CPUID */ + lCPUID = smp_processor_id(); + + /* Update the size of the data entry */ + lDataSize += sizeof(lCPUID); + } + + /* Lock the kernel */ + spin_lock_irqsave(&sSpinLock, lFlags); + + /* The following time calculations have to be done within the spinlock because + otherwise the event order could be inverted. */ + + /* Get the time of the event */ + do_gettimeofday(&lTime); + + /* Compute the time delta between this event and the time at which this buffer was started */ + lTimeDelta = (lTime.tv_sec - sBufferStartTime.tv_sec) * 1000000 + + (lTime.tv_usec - sBufferStartTime.tv_usec); + + /* Is there enough space left in the write buffer */ + if(sWritPos + lDataSize > sWritLimit) + { + /* Have we already switched buffers and informed the daemon of it */ + if(sSignalSent == TRUE) + { + /* We've lost another event */ + sEventsLost++; + + /* Bye, bye, now */ + spin_unlock_irqrestore(&sSpinLock, lFlags); + return -ENOMEM; + } + + /* We need to inform the daemon */ + lSendSignal = TRUE; + + /* Switch buffers */ + tracer_switch_buffers(lTime); + + /* Recompute the time delta since sBufferStartTime has changed because of the buffer change */ + lTimeDelta = (lTime.tv_sec - sBufferStartTime.tv_sec) * 1000000 + + (lTime.tv_usec - sBufferStartTime.tv_usec); + } + + /* Write the CPUID to the tracing buffer, if required */ + if((sLogCPUID == TRUE) && (pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START)) + tracer_write_to_buffer(sWritPos, + &lCPUID, + sizeof(lCPUID)); + + /* Write event type to tracing buffer */ + tracer_write_to_buffer(sWritPos, + &pmEventID, + sizeof(pmEventID)); + + /* Write event time delta to tracing buffer */ + tracer_write_to_buffer(sWritPos, + &lTimeDelta, + sizeof(lTimeDelta)); + + /* Do we log event details */ + if(test_bit(pmEventID, &sLogEventDetailsMask)) + { + /* Write event structure */ + tracer_write_to_buffer(sWritPos, + pmEventStruct, + sEventStructSize[pmEventID]); + + /* Write string if any */ + if(lVarDataLen) + tracer_write_to_buffer(sWritPos, + lVarDataBeg, + lVarDataLen); + } + + /* Write the length of the event description */ + tracer_write_to_buffer(sWritPos, + &lDataSize, + sizeof(lDataSize)); + + /* Should the tracing daemon be notified */ + if(lSendSignal == TRUE) + { + /* Remember that a signal has been sent */ + sSignalSent = TRUE; + + /* Unlock the kernel */ + spin_unlock_irqrestore(&sSpinLock, lFlags); + + /* Setup signal information */ + lSigInfo.si_signo = SIGIO; + lSigInfo.si_errno = 0; + lSigInfo.si_code = SI_KERNEL; + + /* DEBUG */ +#if 0 + printk("<1> Sending SIGIO to %d \n", sDaemonTaskStruct->pid); +#endif + + /* Signal the tracing daemon */ + send_sig_info(SIGIO, &lSigInfo, sDaemonTaskStruct); + } + else + /* Unlock the kernel */ + spin_unlock_irqrestore(&sSpinLock, lFlags); + + /* Indicate to the caller that everything is OK */ + return 0; +} + +/************************************************************* + * Function : tracer_switch_buffers() + * Description : + * Put the current write buffer to be read and reset put + * the old read buffer to be written to. Set the tracer + * variables in consequence. + * Parameters : + * pmTime, current time + * Return values : + * NONE + * Note : + * This should be called from within a spin_lock. + *************************************************************/ +void tracer_switch_buffers(struct timeval pmTime) +{ + char* lTempBuf; /* Temporary buffer pointer */ + char* lTempBufEnd; /* Temporary buffer end pointer */ + char* lInitWritPos; /* Initial write position */ + uint8_t lDataSize; /* Size of tracing data */ + uint8_t lEventID; /* Event ID of last event */ + uint8_t lCPUID; /* CPUID of currently runing process */ + uint32_t lSizeLost; /* Size delta between last event and end of buffer */ + trace_time_delta lTimeDelta; /* The time elapsed between now and the last event */ + trace_buffer_start lStartBufferEvent; /* Start of the new buffer event */ + + /* Remember initial write position */ + lInitWritPos = sWritPos; + + /* Write the end event at the write of the buffer */ + + /* Write the CPUID to the tracing buffer, if required */ + if(sLogCPUID == TRUE) + { + lCPUID = smp_processor_id(); + tracer_write_to_buffer(sWritPos, + &lCPUID, + sizeof(lCPUID)); + } + + /* Write event type to tracing buffer */ + lEventID = TRACE_EV_BUFFER_END; + tracer_write_to_buffer(sWritPos, + &lEventID, + sizeof(lEventID)); + + /* Write event time delta to tracing buffer */ + lTimeDelta = 0; + tracer_write_to_buffer(sWritPos, + &lTimeDelta, + sizeof(lTimeDelta)); + + /* Get size lost */ + lSizeLost = sWritBufEnd - lInitWritPos; + + /* Write size lost at the end of the buffer */ + *((uint32_t*) (sWritBufEnd - sizeof(lSizeLost))) = lSizeLost; + + /* Switch buffers */ + lTempBuf = sReadBuf; + sReadBuf = sWritBuf; + sWritBuf = lTempBuf; + + /* Set buffer ends */ + lTempBufEnd = sReadBufEnd; + sReadBufEnd = sWritBufEnd; + sWritBufEnd = lTempBufEnd; + + /* Set read limit */ + sReadLimit = sReadBufEnd; + + /* Set write limit */ + sWritLimit = sWritBufEnd - TRACER_LAST_EVENT_SIZE; + + /* Set write position */ + sWritPos = sWritBuf; + + /* Increment buffer ID */ + sBufferID++; + + /* Set the time of begining of this buffer */ + sBufferStartTime = pmTime; + + /* Write the start of buffer event */ + lStartBufferEvent.ID = sBufferID; + lStartBufferEvent.Time = pmTime; + + /* Write event type to tracing buffer */ + lEventID = TRACE_EV_BUFFER_START; + tracer_write_to_buffer(sWritPos, + &lEventID, + sizeof(lEventID)); + + /* Write event time delta to tracing buffer */ + lTimeDelta = 0; + tracer_write_to_buffer(sWritPos, + &lTimeDelta, + sizeof(lTimeDelta)); + + /* Write event structure */ + tracer_write_to_buffer(sWritPos, + &lStartBufferEvent, + sizeof(lStartBufferEvent)); + + /* Compute the data size */ + lDataSize = sizeof(lEventID) + + sizeof(lTimeDelta) + + sizeof(lStartBufferEvent) + + sizeof(lDataSize); + + /* Write the length of the event description */ + tracer_write_to_buffer(sWritPos, + &lDataSize, + sizeof(lDataSize)); +} + +/************************************************************* + * Function : tracer_ioctl() + * Description : "Ioctl" file op + * Parameters : + * pmInode, the inode associated with the device + * pmFile, file structure given to the acting process + * pmCmd, command given by the caller + * pmArg, arguments to the command + * Return values : + * >0, In case the caller requested the number of events + * lost. + * 0, Everything went OK + * -ENOSYS, no such command + * -EINVAL, tracer not properly configured + * -EBUSY, tracer can't be reconfigured while in operation + * -ENOMEM, no more memory + * Note : + * In the future, this function should check to make sure + * that it's the server that make thes ioctl. + *************************************************************/ +int tracer_ioctl(struct inode* pmInode, + struct file* pmFile, + unsigned int pmCmd, + unsigned long pmArg) +{ + trace_start lStartEvent; /* Event marking the begining of the trace */ + unsigned long int lFlags; /* CPU flags for lock */ + trace_buffer_start lStartBufferEvent; /* Start of the new buffer event */ + + /* If the tracer is started, the configuration can't be modified */ + if((sTracerStarted == TRUE) && (pmCmd != TRACER_STOP) && (pmCmd != TRACER_DATA_COMITTED)) + return -EBUSY; + + /* Depending on the command executed */ + switch(pmCmd) + { + /* Start the tracer */ + case TRACER_START : + /* Check if the device has been properly set up */ + if(((sUseSyscallEIPBounds == TRUE) + &&(sSyscallEIPDepthSet == TRUE)) + ||((sUseSyscallEIPBounds == TRUE) + &&((sLowerEIPBoundSet != TRUE) + ||(sUpperEIPBoundSet != TRUE))) + ||((sTracingPID == TRUE) + &&(sTracingPGRP == TRUE))) + return -EINVAL; + + /* Set the kernel-side trace configuration */ + if(trace_set_config(trace, + sSyscallEIPDepthSet, + sUseSyscallEIPBounds, + sSyscallEIPDepth, + sLowerEIPBound, + sUpperEIPBound) < 0) + return -EINVAL; + + /* Always log the start event and the buffer start event */ + set_bit(TRACE_EV_BUFFER_START, &sTracedEvents); + set_bit(TRACE_EV_BUFFER_START, &sLogEventDetailsMask); + set_bit(TRACE_EV_START, &sTracedEvents); + set_bit(TRACE_EV_START, &sLogEventDetailsMask); + + /* Get the time of start */ + do_gettimeofday(&sBufferStartTime); + + /* Set the event description */ + lStartBufferEvent.ID = sBufferID; + lStartBufferEvent.Time = sBufferStartTime; + + /* Set the event description */ + lStartEvent.MagicNumber = TRACER_MAGIC_NUMBER; +#ifdef __i386__ + lStartEvent.ArchType = TRACE_ARCH_TYPE_I386; +#endif +#ifdef __powerpc__ + lStartEvent.ArchType = TRACE_ARCH_TYPE_PPC; +#endif + lStartEvent.SystemType = TRACE_SYS_TYPE_VANILLA_LINUX; + lStartEvent.MajorVersion = TRACER_VERSION_MAJOR; + lStartEvent.MinorVersion = TRACER_VERSION_MINOR; + lStartEvent.BufferSize = sBufSize; + lStartEvent.EventMask = sTracedEvents; + lStartEvent.DetailsMask = sLogEventDetailsMask; + lStartEvent.LogCPUID = sLogCPUID; + + /* We can start tracing */ + sTracerStarted = TRUE; + + /* Trace the buffer start event */ + trace(TRACE_EV_BUFFER_START, &lStartBufferEvent); + + /* Trace the start event */ + trace(TRACE_EV_START, &lStartEvent); + + /* Reregister custom events to make sure custom event definitions are part of the trace */ + trace_reregister_custom_events(); + break; + + /* Stop the tracer */ + case TRACER_STOP : + /* Stop tracing */ + sTracerStarted = FALSE; + + /* Switch the buffers to ensure that the end of the buffer mark is set (time isn't important) */ + tracer_switch_buffers(sBufferStartTime); + break; + + /* Set the tracer to the default configuration */ + case TRACER_CONFIG_DEFAULT : + tracer_set_default_config(); + break; + + /* Set the memory buffers the daemon wants us to use */ + case TRACER_CONFIG_MEMORY_BUFFERS : + /* Is the given size "reasonnable" */ + if(pmArg < TRACER_MIN_BUF_SIZE) + return -EINVAL; + + /* Set the buffer's size */ + return tracer_set_buffer_size(pmArg); + break; + + /* Trace the given events */ + case TRACER_CONFIG_EVENTS : + if(copy_from_user(&sTracedEvents, (void*) pmArg, sizeof(sTracedEvents))) + return -EFAULT; + break; + + /* Record the details of the event, or not */ + case TRACER_CONFIG_DETAILS : + if(copy_from_user(&sLogEventDetailsMask, (void*) pmArg, sizeof(sLogEventDetailsMask))) + return -EFAULT; + break; + + /* Record the CPUID associated with the event */ + case TRACER_CONFIG_CPUID : + sLogCPUID = TRUE; + break; + + /* Trace only one process */ + case TRACER_CONFIG_PID : + sTracingPID = TRUE; + sTracedPID = pmArg; + break; + + /* Trace only the given process group */ + case TRACER_CONFIG_PGRP : + sTracingPGRP = TRUE; + sTracedPGRP = pmArg; + break; + + /* Trace the processes of a given group of users */ + case TRACER_CONFIG_GID : + sTracingGID = TRUE; + sTracedGID = pmArg; + break; + + /* Trace the processes of a given user */ + case TRACER_CONFIG_UID : + sTracingUID = TRUE; + sTracedUID = pmArg; + break; + + /* Set the call depth a which the EIP should be fetched on syscall */ + case TRACER_CONFIG_SYSCALL_EIP_DEPTH : + sSyscallEIPDepthSet = TRUE; + sSyscallEIPDepth = pmArg; + break; + + /* Set the lowerbound address from which EIP is recorded on syscall */ + case TRACER_CONFIG_SYSCALL_EIP_LOWER : + /* We are using bounds for fetching the EIP where syscall was made */ + sUseSyscallEIPBounds = TRUE; + + /* Set the lower bound */ + sLowerEIPBound = (void*) pmArg; + + /* The lower bound has been set */ + sLowerEIPBoundSet = TRUE; + break; + + /* Set the upperbound address from which EIP is recorded on syscall */ + case TRACER_CONFIG_SYSCALL_EIP_UPPER : + /* We are using bounds for fetching the EIP where syscall was made */ + sUseSyscallEIPBounds = TRUE; + + /* Set the lower bound */ + sUpperEIPBound = (void*) pmArg; + + /* The lower bound has been set */ + sUpperEIPBoundSet = TRUE; + break; + + /* The daemon has comitted the last trace */ + case TRACER_DATA_COMITTED : +#if 0 + printk("Tracer: Data has been comitted \n"); +#endif + + /* Safely set the signal sent flag to FALSE */ + spin_lock_irqsave(&sSpinLock, lFlags); + sSignalSent = FALSE; + spin_unlock_irqrestore(&sSpinLock, lFlags); + break; + + /* Get the number of events lost */ + case TRACER_GET_EVENTS_LOST : + return sEventsLost; + break; + + /* Unknow command */ + default : + return -ENOSYS; + } + + /* Everything went OK */ + return 0; +} + +/************************************************************* + * Function : tracer_mmap() + * Description : "Mmap" file op + * Parameters : + * pmInode, the inode associated with the device + * pmFile, file structure given to the acting process + * pmVmArea, Virtual memory area description structure + * Return values : + * 0 if ok + * -EAGAIN, when remap failed + ************************************************************/ +int tracer_mmap(struct file* pmFile, + struct vm_area_struct* pmVmArea) +{ + int lRetValue; /* Function's return value */ + + /* Remap trace buffer into the process's memory space */ + lRetValue = tracer_mmap_region((char*) pmVmArea->vm_start, + sTracBuf, + pmVmArea->vm_end - pmVmArea->vm_start); + +#if 0 + printk("Tracer: Trace buffer virtual address => 0x%08X \n", (uint32_t)sTracBuf); + printk("Tracer: Trace buffer physical address => 0x%08X \n", (uint32_t)virt_to_phys(sTracBuf)); + printk("Tracer: Trace buffer virtual address in daemon space => 0x%08X \n", (uint32_t)pmVmArea->vm_start); + printk("Tracer: Trace buffer physical address in daemon space => 0x%08X \n", (uint32_t)virt_to_phys((void*)pmVmArea->vm_start)); +#endif + + /* Tell the caller that the memory mapping worked OK */ + return lRetValue; +} + +/************************************************************* + * Function : tracer_open() + * Description : "Open" file op + * Parameters : + * pmInode, the inode associated with the device + * pmFile, file structure given to the acting process + * Return values : + * 0, everything went OK + * -ENODEV, no such device. + * -EBUSY, the tracer is already in use. + ************************************************************/ +int tracer_open(struct inode* pmInode, + struct file* pmFile) +{ + int lDevMinor = MINOR(pmInode->i_rdev) & 0xf; /* Device minor number */ + + /* Don't allow more than one device of this type */ + if(lDevMinor > 0) + return -ENODEV; + + /* Don't allow the device to be open more than once */ + if(sOpenCount) + return -EBUSY; + + /* Fetch the task structure of the process that opened the device */ + sDaemonTaskStruct = current; + +#if 0 + /* DEBUG */ + printk("<1>Process %d opened the tracing device \n", sDaemonTaskStruct->pid); +#endif + + /* Lock the device */ + sOpenCount++; + +#ifdef MODULE + /* Increment module usage */ + MOD_INC_USE_COUNT; +#endif + + /* Everything is OK */ + return 0; +} + +/************************************************************* + * Function : tracer_release() + * Description : "Release" file op + * Parameters : + * pmInode, the inode associated with the device + * pmFile, file structure given to the acting process + * Return values : + * 0, everything went OK + * Note : + * It is assumed that if the tracing daemon dies, exits + * or simply stops existing, the kernel or "someone" will + * call tracer_release. Otherwise, we're in trouble ... + *************************************************************/ +int tracer_release(struct inode* pmInode, + struct file* pmFile) +{ + /* Did we loose any events */ + if(sEventsLost > 0) + printk("<1>Tracer: Lost %d events \n", sEventsLost); + + /* Reset the daemon PID */ + sDaemonTaskStruct = NULL; + + /* Free the current buffers, if any */ + if(sTracBuf != NULL) + rvfree(sTracBuf, sAllocSize); + + /* Reset the read and write buffers */ + sTracBuf = NULL; + sWritBuf = NULL; + sReadBuf = NULL; + sWritBufEnd = NULL; + sReadBufEnd = NULL; + sWritPos = NULL; + sReadLimit = NULL; + sWritLimit = NULL; + + /* Reset the tracer's configuration */ + tracer_set_default_config(); + sTracerStarted = FALSE; + + /* Reset number of bytes recorded and number of events lost */ + sBufReadComplete = 0; + sSizeReadIncomplete = 0; + sEventsLost = 0; + + /* Reset signal sent */ + sSignalSent = FALSE; + + /* Unlock the device */ + sOpenCount--; + +#ifdef MODULE + /* Decrement module usage */ + MOD_DEC_USE_COUNT; +#endif + + /* Tell the caller that everything is OK */ + return 0; +} + +/************************************************************* + * Function : tracer_fsync() + * Description : "Fsync" file op + * Parameters : + * pmFile, file structure given to the acting process + * pmDEntry, dentry associated with file + * Return values : + * 0, everything went OK + * Note : + * We need to look the modifications of the values because + * they are read and written by trace(). + * Sonia : ne m oublie pas, je suis toujours a toi.... + *************************************************************/ +int tracer_fsync(struct file* pmFile, + struct dentry* pmDEntry) +{ + unsigned long int lFlags; /* CPU flags for lock */ + + /* Lock the kernel */ + spin_lock_irqsave(&sSpinLock, lFlags); + + /* Reset the write positions */ + sWritPos = sWritBuf; + + /* Reset read limit */ + sReadLimit = sReadBuf; + + /* Reset bytes recorded */ + sBufReadComplete = 0; + sSizeReadIncomplete = 0; + sEventsLost = 0; + + /* Reset signal sent */ + sSignalSent = FALSE; + + /* Unlock the kernel */ + spin_unlock_irqrestore(&sSpinLock, lFlags); + + /* Tell the caller that everything is OK */ + return 0; +} + +/************************************************************* + * Function : tracer_set_buffer_size() + * Description : + * Sets the size of the buffers containing the trace data. + * Parameters : + * pmSize, Size of buffers + * Return values : + * 0, Size setting went OK + * -ENOMEM, unable to get a hold of memory for tracer + *************************************************************/ +int tracer_set_buffer_size(int pmSize) +{ + int lSizeAlloc; /* Size to be allocated */ + + /* Set size to allocate (= pmSize * 2) and fix it's size to be on a page boundary */ + lSizeAlloc = FIX_SIZE(pmSize << 1); + + /* Free the current buffers, if any */ + if(sTracBuf != NULL) + rvfree(sTracBuf, sAllocSize); + + /* Allocate space for the tracing buffers */ + if((sTracBuf = (char*) rvmalloc(lSizeAlloc)) == NULL) + return -ENOMEM; + + /* Remember the size set */ + sBufSize = pmSize; + sAllocSize = lSizeAlloc; + + /* Set the read and write buffers */ + sWritBuf = sTracBuf; + sReadBuf = sTracBuf + sBufSize; + + /* Set end of buffers */ + sWritBufEnd = sWritBuf + sBufSize; + sReadBufEnd = sReadBuf + sBufSize; + + /* Set write position */ + sWritPos = sWritBuf; + + /* Set read limit */ + sReadLimit = sReadBuf; + + /* Set write limit */ + sWritLimit = sWritBufEnd - TRACER_LAST_EVENT_SIZE; + + /* All is OK */ + return 0; +} + +/************************************************************* + * Function : tracer_set_default_config() + * Description : Sets the tracer in its default config + * Parameters : + * NONE + * Return values : + * 0, everything went OK + * -ENOMEM, unable to get a hold of memory for tracer + *************************************************************/ +int tracer_set_default_config(void) +{ + int i; /* Generic index */ + int lError = 0; /* Error, if any */ + + /* Initialize the event mask */ + sTracedEvents = 0; + + /* Initialize the event mask with all existing events with their details*/ + for(i = 0; i <= TRACE_EV_MAX; i++) + { + set_bit(i, &sTracedEvents); + set_bit(i, &sLogEventDetailsMask); + } + + /* Forget about the CPUID */ + sLogCPUID = FALSE; + + /* We aren't tracing any PID or GID in particular */ + sTracingPID = FALSE; + sTracingPGRP = FALSE; + sTracingGID = FALSE; + sTracingUID = FALSE; + + /* We aren't looking for a particular call depth */ + sSyscallEIPDepthSet = FALSE; + + /* We aren't going to place bounds on syscall EIP fetching */ + sUseSyscallEIPBounds = FALSE; + sLowerEIPBoundSet = FALSE; + sUpperEIPBoundSet = FALSE; + + /* Set the kernel trace configuration to it's basics */ + trace_set_config(trace, + sSyscallEIPDepthSet, + sUseSyscallEIPBounds, + 0, + 0, + 0); + + /* Return the error code */ + return lError; +} + +/************************************************************** + * Function : tracer_init() + * Description : Tracer initialization function. + * Parameters : + * NONE + * Return values : + * 0, everything went OK + * -ENOMEM, unable to get a hold of memory for tracer + **************************************************************/ +int tracer_init(void) +{ + int lError = 0; /* Error, if any */ + + /* Initialize configuration */ + if((lError = tracer_set_default_config()) < 0) + return lError; + + /* Initialize open count */ + sOpenCount = 0; + + /* Initialize tracer lock */ + sTracLock = 0; + + /* Initialize signal sent */ + sSignalSent = FALSE; + + /* Initialize bytes read and events lost */ + sBufReadComplete = 0; + sSizeReadIncomplete = 0; + sEventsLost = 0; + + /* Initialize buffer ID */ + sBufferID = 0; + + /* Initialize tracing daemon task structure */ + sDaemonTaskStruct = NULL; + + /* Initialize spin lock */ + sSpinLock = SPIN_LOCK_UNLOCKED; + + /* Register the tracer as a char device */ + sMajorNumber = register_chrdev(0, TRACER_NAME, &sTracerFileOps); + + /* Register the tracer with the kernel */ + register_tracer(trace); + + /* Let the user know about it */ +#if 1 + printk("<1>Tracer: Initialization complete \n"); +#endif + + /* Return error code */ + return lError; +} + +/* Is this loaded as a module */ +#ifdef MODULE +/************************************************************** + * Function : cleanup_module() + * Description : Cleanup of the tracer. + * Parameters : NONE + * Return values : NONE + * Note : The order of the unregesterings is important. First, + * rule out any possibility of getting more trace + * data. Second, rule out any possibility of being read + * by the tracing daemon. Last, free the tracing + * buffer. + **************************************************************/ +void cleanup_module(void) +{ + /* Unregister the tracer from the kernel */ + unregister_tracer(trace); + + /* Unregister the tracer from being a char device */ + unregister_chrdev(sMajorNumber, TRACER_NAME); + + /* Free the current buffers, if any */ + if(sTracBuf != NULL) + rvfree(sTracBuf, sAllocSize); + + /* Paranoia */ + sTracBuf = NULL; +} + +/************************************************************** + * Function : init_module() + * Description : Initialization of the tracer. + * Parameters : + * NONE + * Return values : + * 0, everything went OK + * -ENOMEM, unable to get a hold of memory for tracer + **************************************************************/ +int init_module(void) +#else +/************************************************************** + * Function : tracer_setup() + * Description : Trace setup function. + * Parameters : + * NONE + * Return values : + * 0, everything went OK + * -ENOMEM, unable to get a hold of memory for tracer + **************************************************************/ +__initfunc(int tracer_setup(void)) +#endif /* MODULE */ +{ + /* Initialize the tracer and return status */ + return tracer_init(); +} + diff -urP linux-2.2.18/drivers/trace/tracer.h linux-2.2.18-ltt-0.9.4/drivers/trace/tracer.h --- linux-2.2.18/drivers/trace/tracer.h Wed Dec 31 19:00:00 1969 +++ linux-2.2.18-ltt-0.9.4/drivers/trace/tracer.h Mon Mar 19 15:59:23 2001 @@ -0,0 +1,120 @@ +/* + * drivers/trace/tracer.h + * + * Copyright (C) 1999, Karim Yaghmour + * + * This contains the necessary definitions the system tracer + */ + +#ifndef _TRACER_H +#define _TRACER_H + +/* Logic values */ +#define FALSE 0 +#define TRUE 1 + +/* Tracer properties */ +#define TRACER_NAME "tracer" /* Name of the device as seen in /proc/devices */ + +/* Tracer buffer information */ +#define TRACER_DEFAULT_BUF_SIZE 50000 /* Default size of tracing buffer */ +#define TRACER_MIN_BUF_SIZE 1000 /* Minimum size of tracing buffer */ +#define TRACER_MAX_BUF_SIZE 500000 /* Maximum size of tracing buffer */ + +/* Local definitions */ +typedef uint32_t trace_time_delta; /* The type used to start the time delta between events */ +typedef uint64_t trace_event_mask; /* The event mask type */ + +/* Number of bytes set aside for last event */ +#define TRACER_LAST_EVENT_SIZE (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(trace_time_delta) + sizeof(uint32_t)) + +/* Architecture types */ +#define TRACE_ARCH_TYPE_I386 1 /* i386 system */ +#define TRACE_ARCH_TYPE_PPC 2 /* PPC system */ + +/* System types */ +#define TRACE_SYS_TYPE_VANILLA_LINUX 1 /* Vanilla linux kernel */ + +/* The information logged when the tracing is started */ +#define TRACER_MAGIC_NUMBER 0x000D6B7ED /* That day marks an important historical event ... */ +#define TRACER_VERSION_MAJOR 1 /* Major version number */ +#define TRACER_VERSION_MINOR 8 /* Minor version number */ +typedef struct _trace_start +{ + uint32_t MagicNumber; /* Magic number to identify a trace */ + uint32_t ArchType; /* Type of architecture */ + uint32_t SystemType; /* Operating system type */ + uint8_t MajorVersion; /* Major version of trace */ + uint8_t MinorVersion; /* Minor version of trace */ + + uint32_t BufferSize; /* Size of buffers */ + trace_event_mask EventMask; /* The event mask */ + trace_event_mask DetailsMask; /* Are the event details logged */ + uint8_t LogCPUID; /* Is the CPUID logged */ +} trace_start; + +/* Start and end of trace buffer information */ +typedef struct _trace_buffer_start +{ + struct timeval Time; /* Time stamp of this buffer */ + uint32_t ID; /* Unique buffer ID */ +} trace_buffer_start; + + +/* The configurations possible */ +#define TRACER_START 0 /* Start tracing events using the current configuration */ +#define TRACER_STOP 1 /* Stop tracing */ +#define TRACER_CONFIG_DEFAULT 2 /* Set the tracer to the default configuration */ +#define TRACER_CONFIG_MEMORY_BUFFERS 3 /* Set the memory buffers the daemon wants us to use */ +#define TRACER_CONFIG_EVENTS 4 /* Trace the given events */ +#define TRACER_CONFIG_DETAILS 5 /* Record the details of the event, or not */ +#define TRACER_CONFIG_CPUID 6 /* Record the CPUID associated with the event */ +#define TRACER_CONFIG_PID 7 /* Trace only one process */ +#define TRACER_CONFIG_PGRP 8 /* Trace only the given process group */ +#define TRACER_CONFIG_GID 9 /* Trace the processes of a given group of users */ +#define TRACER_CONFIG_UID 10 /* Trace the processes of a given user */ +#define TRACER_CONFIG_SYSCALL_EIP_DEPTH 11 /* Set the call depth at which the EIP should be fetched on syscall */ +#define TRACER_CONFIG_SYSCALL_EIP_LOWER 12 /* Set the lowerbound address from which EIP is recorded on syscall */ +#define TRACER_CONFIG_SYSCALL_EIP_UPPER 13 /* Set the upperbound address from which EIP is recorded on syscall */ +#define TRACER_DATA_COMITTED 14 /* The daemon has comitted the last trace */ +#define TRACER_GET_EVENTS_LOST 15 /* Get the number of events lost */ + +/* Function prototypes */ +int trace + (uint8_t, + void*); +void tracer_switch_buffers + (struct timeval); +int tracer_ioctl + (struct inode*, + struct file*, + unsigned int, + unsigned long); +int tracer_mmap + (struct file*, + struct vm_area_struct*); +int tracer_open + (struct inode*, + struct file*); +int tracer_release + (struct inode*, + struct file*); +int tracer_fsync + (struct file*, + struct dentry*); +#ifdef MODULE +int init_module + (void); +void cleanup_module + (void); +#else +int tracer_setup + (void); +#endif +int tracer_set_buffer_size + (int); +int tracer_set_default_config + (void); +int tracer_init + (void); +#endif /* _TRACER_H */ diff -urP linux-2.2.18/drivers/trace/tsm_engine.c linux-2.2.18-ltt-0.9.4/drivers/trace/tsm_engine.c --- linux-2.2.18/drivers/trace/tsm_engine.c Wed Dec 31 19:00:00 1969 +++ linux-2.2.18-ltt-0.9.4/drivers/trace/tsm_engine.c Mon Mar 19 15:59:23 2001 @@ -0,0 +1,361 @@ +/* + tsm_engine.c : Trace state machine engine. + Copyright (C) 2000 Karim Yaghmour (karym@opersys.com). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + History : + K.Y., 26/05/1999, Initial typing. +*/ + +#include + +#include +#include "tracer.h" +#include "tsm_engine.h" + +/* The table containing all the state machines */ +static trace_state_machine tsm_table[TSM_MAX_STATE_MACHINES] = {{0}}; + +/* The number of triggers active for each event */ +int tsm_event_trigger_count[TRACE_EV_MAX] = {{0}}; + +/************************************************************** + * Function : tsm_event_handler() + * Description : + * Handles event occurences by activating the state machines + * in occordance with the descriptions given at their + * initialization. + * Parameters : + * pmEventID, ID of event as defined in linux/trace.h + * pmEventStruct, struct describing the event + * Return values : + * NONE + * Note : + **************************************************************/ +int tsm_event_handler(uint8_t pmEventID, + void* pmEventStruct) +{ + trace_state* pCurrentState; /* Current state machine state */ + trace_state_trigger* pTrigger; /* Generic pointer to trigger */ + + /* Loop around all the state machines */ + for(i = 0; i < TSM_MAX_STATE_MACHINES; i++) + { + /* Is this state machine active */ + if(tsm_table[i].nb_states == 0) + continue; + + /* Get the current state */ + pCurrentState = tsm_table[i].current_state; + + /* Go through the trigger list */ + for(pTrigger = pCurrentState->triggers; + pTrigger != NULL; + pTrgger = pTrigger->next) + { + /* Does this trigger react to this event */ + if(pTrigger->id == pmEventID) + { + /* Get the incoming state */ + pNextState = pTrigger->result_state; + + /* Call the exit function of the current state, if any */ + if(pCurrentState->exit_func != NULL) + pCurrentState->exit_func(pCurrentState->id, + pNextState->id, + pmEventID, + pmEventStruct); + + /* Call the transition function of the trigger */ + if(pTrigger->transit_func != NULL) + pTrigger->transit_func(pCurrentState->id, + pNextState->id, + pmEventID, + pmEventStruct); + + /* Call the entry function of the next state */ + if(pNextState->entry_func != NULL) + pNextState->entry_func(pCurrentState->id, + pNextState->id, + pmEventID, + pmEventStruct); + + /* Remember state status */ + tsm_table[i].current_state = pNextState; + tsm_table[i].previous_state = pCurrentState; + } + } + } +} + +/************************************************************** + * Function : tsm_compile_and_register_state_machine() + * Description : + * Compiles a given state machine into an operation state + * machine usable by the tsm engine. + * Parameters : + * pmStateTable, Table describing the different states of the + * state machine. + * pmTriggerTable, Table describing the different triggers + * of the state machine. + * Return values : + * Id of state machine created. + * -ENODEV, No entries in the main tsm table available. + * -EINVAL, The given description is invalid. + * Note : + * If the user is dumb enough to put entries in the state + * table that have the same state ID then all but the + * first one will be ignored. + **************************************************************/ +int tsm_compile_and_register_state_machine(tsm_state_description* pmStateTable, + tsm_trigger_description* pmTriggerTable) +{ + int i; /* Generic index */ + int lTSMID; /* Trace state machine ID */ + int lNbState; /* Number of states machine has */ + trace_state* pLastState; /* Last allocated state */ + trace_state* pState; /* Generic pointer to machine state */ + trace_state* pOriginState; /* State from which a trigger leaves */ + trace_state* pDestinationState; /* State to which a trigger leads */ + trace_event_mask lEventMask; /* Events that have to be traced */ + trace_state_trigger* pTrigger; /* Generic pointer to trigger */ + + /* Find an empty entry in the tsm table */ + for(i = 0; i < TSM_MAX_STATE_MACHINES; i++) + if(tsm_table[i].nb_states == 0) + lTSMID = i; + + /* Did we find anything */ + if(i == TSM_MAX_STATE_MACHINES) + return -ENODEV; + + /* Make sure state machine is correctly set up (paranoia's sake) */ + tsm_table[lTSMID].state_list = NULL; + tsm_table[lTSMID].current_state = NULL; + tsm_table[lTSMID].previous_state = NULL; + + /* Initialize variables for building state machine */ + lNbState = 0; + pLastState = NULL; + + /* Loop around the state machine description to build our own internal structures */ + for(i = 0; pmStateTable[i].id == 0; i++) + { + /* Is this the first state to be created */ + if(tsm_table[lTSMID].state_list == NULL) + { + /* Allocate first entry in tsm */ + tsm_table[lTSMID].state_list = kmalloc(GFP_KERNEL, sizeof(trace_state)); + + /* This is the last create state */ + pLastState = tsm_table[lTSMID].state_list; + } + else + { + /* Allocate next entry in tsm */ + pLastState->next = kmalloc(GFP_KERNEL, sizeof(trace_state)); + + /* This is the last create state */ + pLastState = pLastState->next; + } + + /* Initialize state entry */ + pLastState->id = pmStateTable[i].id; + pLastState->entry_func = pmStateTable[i].entry_func; + pLastState->exit_func = pmStateTable[i].exit_func; + pLastState->triggers = NULL; + pLastState->next = NULL; + + /* Increment number of states */ + tsm_table[lTSMID].nb_states++; + } + + /* The state machine starts at the first state given */ + tsm_table[lTSMID].current_state = tsm_table[lTSMID].state_list; + + /* Loop around the state machine transition triggers while filling the state strucutres */ + for(i = 0; pmTriggerTable[i].state_id == 0; i++) + { + /* Loop around the state list to find the designated states */ + for(pState = tsm_table[lTSMID].current_state; + (pState != NULL); + pState = pState->next) + { + /* Is this the origin state */ + if(pState->id == pmTriggerTable[i].origin_state_id) + pOriginState = pState; + + /* Is this the destination state */ + if(pState->id == pmTriggerTable[i].destination_state_id) + pDestinationState = pState; + } + + /* Did we find the designated states */ + if((pOriginState == NULL) || (pDestinationState == NULL)) + { + /* There's a mistake with this machine description, free the state machine */ + tsm_unregister_state_machine(lTSMID); + + /* Tell this guy to go draw his machine before coding it ... */ + return -EINVAL; + } + + /* Is this the first trigger to be added for this state */ + if(pOriginState->triggers == NULL) + { + /* Allocate space for first trigger */ + pOriginState->triggers = kmalloc(GFP_KERNEL, sizeof(trace_state_trigger)); + + /* This is the trigger we are adding */ + pTrigger = pOriginState->triggers; + } + else + /* Go to the last trigger in the trigger list */ + for(pTrigger = pState->triggers; + pTrigger->Next != NULL; + pTrgger = pTrigger->next); + + /* Setup the newly allocated trigger */ + pTrigger->id = pmTriggerTable[i].trigger_id; + pTrigger->transit_func = pmTriggerTable[i].transic_func; + pTrigger->result_state = pDestinationState; + pTrigger->next = NULL; + + /* Did we already register a callback for this event */ + if(tsm_event_trigger_count[pTrigger->id] == 0) + /* Register the state machine handler to get this event */ + trace_register_callback(&tsm_event_handler, pTrigger->id); + + /* This event has one more trigger "activatable" on it */ + tsm_event_trigger_count[pTrigger->id]++; + } + + /* Give the caller the ID of the created state machine */ + return lTSMID; +} + +/************************************************************** + * Function : tsm_unregister_state_machine() + * Description : + * Frees the ressources used by the given state machine. + * Parameters : + * pmTSM, State machine ID. + * Return values : + * NONE. + * Note : + **************************************************************/ +void tsm_unregister_state_machine(int pmTSM) +{ + trace_state* pNextState; /* Next state in list */ + trace_state* pState; /* Generic pointer to machine state */ + trace_state_trigger* pNextTrigger; /* Next trigger in list */ + trace_state_trigger* pTrigger; /* Generic pointer to trigger */ + + /* Is this entry being used */ + if(tsm_table[pmTSM].nb_states == 0) + /* We're done */ + return; + + /* Loop around all the defined states */ + for(pState = tsm_table[i].state_list; + pState != NULL;) + { + /* Remember the next state */ + pNextState = pState->next; + + /* Loop around all the triggers */ + for(pTrigger = pState->triggers; + pTrigger != NULL;) + { + /* Remember the next trigger */ + pNextTrigger = pTrigger->next; + + /* Decrement the trigger count of the corresponding event */ + tsm_event_trigger_count[pTrigger->id]--; + + /* Are there any more triggers hooked on this event */ + if(tsm_event_trigger_count[pTrigger->id] == 0) + /* Unregister the callback for this event */ + trace_unregister_callback(&tsm_event_handler, pTrigger->id); + + /* Free this trigger */ + kfree(pTrigger); + + /* Go to next trigger in list */ + pState = pNextTrigger; + } + + /* Free this state */ + kfree(pState); + + /* Go to next state in list */ + pState = pNextState; + } + + /* Reinitialize this machine state entry */ + tsm_table[pmTSM].nb_states = 0; + tsm_table[pmTSM].state_list = NULL; + tsm_table[pmTSM].current_state = NULL; + tsm_table[pmTSM].previous_state = NULL; +} + +/* Is this loaded as a module */ +#ifdef MODULE +/************************************************************** + * Function : cleanup_module() + * Description : + * Cleanup of the trace state machine engine. + * Parameters : + * NONE + * Return values : + * NONE + * Note : + **************************************************************/ +void cleanup_module(void) +{ + /* Loop around the state machine table */ + for(i = 0; i < TSM_MAX_STATE_MACHINES; i++) + /* Unregister the tracer */ + tsm_unregister_state_machine(i); +} + +/************************************************************** + * Function : init_module() + * Description : + * Initialization of the trace state machine engine. + * Parameters : + * NONE + * Return values : + * 0, everything went OK + * -ENOMEM, unable to get a hold of memory for tracer + **************************************************************/ +int init_module(void) +#else +/************************************************************** + * Function : tsm_engine_setup() + * Description : + * Sets up and initializes the trace state machine engine. + * Parameters : + * NONE + * Return values : + * 0, everything went OK + **************************************************************/ +__initfunc(int tsm_engine_setup(void)) +#endif /* MODULE */ +{ + /* Tell the caller that everything is OK */ + return 0; +} diff -urP linux-2.2.18/drivers/trace/tsm_engine.h linux-2.2.18-ltt-0.9.4/drivers/trace/tsm_engine.h --- linux-2.2.18/drivers/trace/tsm_engine.h Wed Dec 31 19:00:00 1969 +++ linux-2.2.18-ltt-0.9.4/drivers/trace/tsm_engine.h Mon Mar 19 15:59:23 2001 @@ -0,0 +1,81 @@ +/* + * drivers/trace/tsm_engine.h + * + * Copyright (C) 2000, Karim Yaghmour (karym@opersys.com) + * + * This contains the necessary definitions the trace state machine engine + */ + +#define TSM_MAX_STATE_MACHINES 5 /* Maximum number of state machines */ + +/* The prototype of a trace state machine callback */ +typedef void (*tsm_callback) (int /* Outgoing state */, + int /* Incoming state */, + int /* Event ID (trigger) */, + void* /* Pointer to event structure */ ); + +/* The description of one of the states of the trace state machine */ +typedef struct _tsm_state_description +{ + int id; /* State ID (never use 0 as a state ID) */ + tsm_callback entry_func; /* The callback called on entry in state */ + tsm_callback exit_func; /* The callback called on exit from state */ +} tsm_state_description; + +/* The description of one of the triggers of one of the states of the trace state machine */ +typedef struct _tsm_trigger_description +{ + int trigger_id; /* Trigger ID */ + int origin_state_id; /* ID of state from which this trigger originates */ + int destination_state_id; /* ID of the state to which this trigger leads */ + tsm_callback transit_func; /* The callback called during transition */ +} tsm_trigger_description; + +/* A state transition trigger */ +typedef struct _trace_state_trigger +{ + int id; /* Event ID that triggers the transition */ + tsm_callback transit_func; /* The callback called during transition */ + + struct _trace_state* result_state; /* State in which we end up in */ + struct _trace_state_trigger* next; /* Next possible transition in list */ +} trace_state_trigger; + +/* A given state of a state machine */ +typedef struct _trace_state +{ + int id; /* State ID (for human understandibility) */ + tsm_callback entry_func; /* The callback called on entry in state */ + tsm_callback exit_func; /* The callback called on exit from state */ + trace_state_trigger* triggers; /* List of possible triggers to other states */ + + struct _trace_state* next; /* Next state in state list */ +} trace_state; + +/* A state machine */ +typedef struct _trace_state_machine +{ + int nb_states; /* Number of states */ + trace_state* state_list; /* State list head */ + trace_state* current_state; /* Machine's current state */ + trace_state* previous_state; /* Machine's previous state */ +} tace_state_machine; + +/* Function prototypes */ +int tsm_event_handler + (uint8_t /* Id of occuring event */, + void* /* Pointer to structure describing event */); +int tsm_compile_and_register_state_machine + (tsm_state_description* /* Table containing state descriptions */, + tsm_trigger_description* /* Table containing trigger descriptions */); +void tsm_unregister_state_machine + (int /* Trace state machine ID */) +#ifdef MODULE +int init_module + (void); +void cleanup_module + (void); +#else +int tsm_engine_setup + (void); +#endif diff -urP linux-2.2.18/fs/buffer.c linux-2.2.18-ltt-0.9.4/fs/buffer.c --- linux-2.2.18/fs/buffer.c Sun Dec 10 19:49:44 2000 +++ linux-2.2.18-ltt-0.9.4/fs/buffer.c Mon Mar 19 15:59:23 2001 @@ -44,6 +44,8 @@ #include #include +#include + #include #include #include @@ -145,12 +147,14 @@ add_wait_queue(&bh->b_wait, &wait); repeat: tsk->state = TASK_UNINTERRUPTIBLE; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_BUF_WAIT_START, 0, 0, NULL); run_task_queue(&tq_disk); if (buffer_locked(bh)) { schedule(); goto repeat; } tsk->state = TASK_RUNNING; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_BUF_WAIT_END, 0, 0, NULL); remove_wait_queue(&bh->b_wait, &wait); bh->b_count--; } diff -urP linux-2.2.18/fs/exec.c linux-2.2.18-ltt-0.9.4/fs/exec.c --- linux-2.2.18/fs/exec.c Sun Dec 10 19:49:44 2000 +++ linux-2.2.18-ltt-0.9.4/fs/exec.c Mon Mar 19 15:59:23 2001 @@ -32,6 +32,8 @@ #include #include +#include + #include #include #include @@ -834,6 +836,11 @@ retval = PTR_ERR(dentry); if (IS_ERR(dentry)) return retval; + + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_EXEC, + 0, + dentry->d_name.len, + dentry->d_name.name); bprm.dentry = dentry; bprm.filename = filename; diff -urP linux-2.2.18/fs/ioctl.c linux-2.2.18-ltt-0.9.4/fs/ioctl.c --- linux-2.2.18/fs/ioctl.c Sun Dec 10 19:49:44 2000 +++ linux-2.2.18-ltt-0.9.4/fs/ioctl.c Mon Mar 19 15:59:23 2001 @@ -8,6 +8,8 @@ #include #include +#include + #include static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) @@ -52,6 +54,10 @@ if (!filp) goto out; error = 0; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_IOCTL, + fd, + cmd, + NULL); switch (cmd) { case FIOCLEX: FD_SET(fd, current->files->close_on_exec); diff -urP linux-2.2.18/fs/open.c linux-2.2.18-ltt-0.9.4/fs/open.c --- linux-2.2.18/fs/open.c Sun Dec 10 19:49:44 2000 +++ linux-2.2.18-ltt-0.9.4/fs/open.c Mon Mar 19 15:59:23 2001 @@ -10,6 +10,8 @@ #include #include +#include + #include asmlinkage int sys_statfs(const char * path, struct statfs * buf) @@ -763,6 +765,10 @@ error = PTR_ERR(f); if (IS_ERR(f)) goto out_error; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_OPEN, + fd, + f->f_dentry->d_name.len, + f->f_dentry->d_name.name); fd_install(fd, f); } out: @@ -843,6 +849,10 @@ filp = fcheck(fd); if (filp) { struct files_struct * files = current->files; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_CLOSE, + fd, + 0, + NULL); files->fd[fd] = NULL; put_unused_fd(fd); FD_CLR(fd, files->close_on_exec); diff -urP linux-2.2.18/fs/read_write.c linux-2.2.18-ltt-0.9.4/fs/read_write.c --- linux-2.2.18/fs/read_write.c Mon Sep 4 13:39:27 2000 +++ linux-2.2.18-ltt-0.9.4/fs/read_write.c Mon Mar 19 15:59:23 2001 @@ -11,6 +11,8 @@ #include #include +#include + #include static loff_t default_llseek(struct file *file, loff_t offset, int origin) @@ -65,6 +67,10 @@ retval = -EINVAL; if (origin <= 2) retval = llseek(file, offset, origin); + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SEEK, + fd, + offset, + NULL); out_putf: fput(file); bad: @@ -98,6 +104,10 @@ offset = llseek(file, ((loff_t) offset_high << 32) | offset_low, origin); + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SEEK, + fd, + offset, + NULL); retval = (int)offset; if (offset >= 0) { @@ -134,6 +144,10 @@ ret = -EINVAL; if (!file->f_op || !(read = file->f_op->read)) goto out; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ, + fd, + count, + NULL); ret = read(file, buf, count, &file->f_pos); out: fput(file); @@ -166,6 +180,10 @@ if (!file->f_op || !(write = file->f_op->write)) goto out; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE, + fd, + count, + NULL); down(&inode->i_sem); ret = write(file, buf, count, &file->f_pos); up(&inode->i_sem); @@ -292,6 +310,10 @@ file = fget(fd); if (!file) goto bad_file; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ, + fd, + count, + NULL); if (file->f_op && file->f_op->read && (file->f_mode & FMODE_READ)) ret = do_readv_writev(VERIFY_WRITE, file, vector, count); fput(file); @@ -313,6 +335,10 @@ file = fget(fd); if (!file) goto bad_file; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE, + fd, + count, + NULL); if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) { down(&file->f_dentry->d_inode->i_sem); ret = do_readv_writev(VERIFY_READ, file, vector, count); @@ -353,6 +379,10 @@ goto out; if (pos < 0) goto out; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ, + fd, + count, + NULL); ret = read(file, buf, count, &pos); out: fput(file); @@ -386,6 +416,10 @@ if (pos < 0) goto out; + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE, + fd, + count, + NULL); down(&file->f_dentry->d_inode->i_sem); ret = write(file, buf, count, &pos); up(&file->f_dentry->d_inode->i_sem); diff -urP linux-2.2.18/fs/select.c linux-2.2.18-ltt-0.9.4/fs/select.c --- linux-2.2.18/fs/select.c Wed May 3 20:16:47 2000 +++ linux-2.2.18-ltt-0.9.4/fs/select.c Mon Mar 19 15:59:23 2001 @@ -15,6 +15,8 @@ #include #include +#include + #include #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) @@ -209,6 +211,10 @@ file = fcheck(i); mask = POLLNVAL; if (file) { + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SELECT, + i /* The fd*/, + __timeout, + NULL); mask = DEFAULT_POLLMASK; if (file->f_op && file->f_op->poll) mask = file->f_op->poll(file, wait); @@ -381,6 +387,10 @@ struct file * file = fcheck(fd); mask = POLLNVAL; if (file != NULL) { + TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_POLL, + fd, + timeout, + NULL); mask = DEFAULT_POLLMASK; if (file->f_op && file->f_op->poll) mask = file->f_op->poll(file, wait); diff -urP linux-2.2.18/include/linux/trace.h linux-2.2.18-ltt-0.9.4/include/linux/trace.h --- linux-2.2.18/include/linux/trace.h Wed Dec 31 19:00:00 1969 +++ linux-2.2.18-ltt-0.9.4/include/linux/trace.h Mon Mar 19 16:05:03 2001 @@ -0,0 +1,388 @@ +/* + * linux/include/linux/trace.h + * + * Copyright (C) 1999, Karim Yaghmour + * + * This contains the necessary definitions for tracing the + * the system. + */ + +#ifndef _LINUX_TRACE_H +#define _LINUX_TRACE_H + +#include +#include + +/* Is kernel tracing enabled */ +#if defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE) +/* The prototype of the tracer call (EventID, *EventStruct) */ +typedef int (*tracer_call) (uint8_t, void*); + +/* This structure contains all the information needed to be known + about the tracing module. */ +struct tracer +{ + /* The tracing routine itself */ + tracer_call trace; + + /* Fetch of eip origin of syscall */ + int fetch_syscall_eip_use_depth; /* Use the given depth */ + int fetch_syscall_eip_use_bounds; /* Find eip in bounds */ + int syscall_eip_depth; /* Call depth at which eip is fetched */ + void* syscall_lower_eip_bound; /* Lower eip bound */ + void* syscall_upper_eip_bound; /* Higher eip bound */ +}; + +/* Maximal size a custom event can have */ +#define CUSTOM_EVENT_MAX_SIZE 8192 + +/* String length limits for custom events creation */ +#define CUSTOM_EVENT_TYPE_STR_LEN 20 +#define CUSTOM_EVENT_DESC_STR_LEN 100 +#define CUSTOM_EVENT_FINAL_STR_LEN 200 + +/* Description of custom event's data */ +typedef struct _event_data_desc +{ + int notfixed; /* Does this data have unfixed length? (0=fixed, 1=variable) */ + int length; /* What is the length of this data field */ +} event_data_desc; + +/* The functions to the tracer management code */ +int register_tracer + (tracer_call /* The tracer function */); +int unregister_tracer + (tracer_call /* The tracer function */); +int trace_set_config + (tracer_call /* The tracer function */, + int /* Use depth to fetch eip */, + int /* Use bounds to fetch eip */, + int /* Detph to fetch eip */, + void* /* Lower bound eip address */, + void* /* Upper bound eip address */); +int trace_register_callback + (tracer_call /* The callback to add */, + uint8_t /* The event ID targeted */); +int trace_unregister_callback + (tracer_call /* The callback to remove */, + uint8_t /* The event ID targeted */); +int trace_get_config + (int* /* Use depth to fetch eip */, + int* /* Use bounds to fetch eip */, + int* /* Detph to fetch eip */, + void** /* Lower bound eip address */, + void** /* Upper bound eip address */); +int trace_create_event + (char* /* String describing event type */, + char* /* String to format event description */, + event_data_desc* /* Table containing data formatting details */); +void trace_destroy_event + (int /* The event ID given by trace_create_event() */); +void trace_reregister_custom_events + (void); +int trace_formatted_event + (int /* The event ID given by trace_create_event() */, + ... /* The parameters to be printed out in the event string */); +int trace_raw_event + (int /* The event ID given by trace_create_event() */, + int /* The size of the raw data */, + void* /* Pointer to the raw event data */); +int trace_event + (uint8_t /* Event ID (as defined in this header file) */, + void* /* Structure describing the event */); + +/* Generic macros */ +#define TRACE_EVENT(ID, DATA) trace_event(ID, DATA) + +/* Traced events */ +#define TRACE_EV_START 0 /* This is to mark the trace's start */ +#define TRACE_EV_SYSCALL_ENTRY 1 /* Entry in a given system call */ +#define TRACE_EV_SYSCALL_EXIT 2 /* Exit from a given system call */ +#define TRACE_EV_TRAP_ENTRY 3 /* Entry in a trap */ +#define TRACE_EV_TRAP_EXIT 4 /* Exit from a trap */ +#define TRACE_EV_IRQ_ENTRY 5 /* Entry in an irq */ +#define TRACE_EV_IRQ_EXIT 6 /* Exit from an irq */ +#define TRACE_EV_SCHEDCHANGE 7 /* Scheduling change */ +#define TRACE_EV_KERNEL_TIMER 8 /* The kernel timer routine has been called */ +#define TRACE_EV_SOFT_IRQ 9 /* Hit key part of soft-irq management */ +#define TRACE_EV_PROCESS 10 /* Hit key part of process management */ +#define TRACE_EV_FILE_SYSTEM 11 /* Hit key part of file system */ +#define TRACE_EV_TIMER 12 /* Hit key part of timer management */ +#define TRACE_EV_MEMORY 13 /* Hit key part of memory management */ +#define TRACE_EV_SOCKET 14 /* Hit key part of socket communication */ +#define TRACE_EV_IPC 15 /* Hit key part of System V IPC */ +#define TRACE_EV_NETWORK 16 /* Hit key part of network communication */ + +#define TRACE_EV_BUFFER_START 17 /* Mark the begining of a trace buffer */ +#define TRACE_EV_BUFFER_END 18 /* Mark the ending of a trace buffer */ +#define TRACE_EV_NEW_EVENT 19 /* New event type */ +#define TRACE_EV_CUSTOM 20 /* Custom event */ + +/* Number of traced events */ +#define TRACE_EV_MAX TRACE_EV_CUSTOM + +/* Structures and macros for events */ +/* TRACE_SYSCALL_ENTRY */ +typedef struct _trace_syscall_entry +{ + uint8_t syscall_id; /* Syscall entry number in entry.S */ + uint32_t address; /* Address from which call was made */ +} trace_syscall_entry; + +/* TRACE_TRAP_ENTRY */ +typedef struct _trace_trap_entry +{ + uint16_t trap_id; /* Trap number */ + uint32_t address; /* Address where trap occured */ +} trace_trap_entry; +#define TRACE_TRAP_ENTRY(ID, EIP) \ + do \ + {\ + trace_trap_entry trap_event;\ + trap_event.trap_id = ID;\ + trap_event.address = EIP;\ + trace_event(TRACE_EV_TRAP_ENTRY, &trap_event);\ + } while(0); + +/* TRACE_IRQ_ENTRY */ +typedef struct _trace_irq_entry +{ + uint8_t irq_id; /* IRQ number */ + uint8_t kernel; /* Are we executing kernel code */ +} trace_irq_entry; +#define TRACE_IRQ_ENTRY(ID, KERNEL) \ + do \ + {\ + trace_irq_entry irq_entry;\ + irq_entry.irq_id = ID;\ + irq_entry.kernel = KERNEL;\ + trace_event(TRACE_EV_IRQ_ENTRY, &irq_entry);\ + } while(0); + +/* TRACE_SCHEDCHANGE */ +typedef struct _trace_schedchange +{ + pid_t out; /* Outgoing process */ + pid_t in; /* Incoming process */ + uint32_t out_state; /* Outgoing process' state */ +} trace_schedchange; +#define TRACE_SCHEDCHANGE(OUT, IN, OUT_STATE) \ + do \ + {\ + trace_schedchange sched_event;\ + sched_event.out = OUT;\ + sched_event.in = IN;\ + sched_event.out_state = OUT_STATE; \ + trace_event(TRACE_EV_SCHEDCHANGE, &sched_event);\ + } while(0); + +/* TRACE_SOFT_IRQ */ +#define TRACE_EV_SOFT_IRQ_BOTTOM_HALF 1 /* Conventional bottom-half */ +#define TRACE_EV_SOFT_IRQ_SOFT_IRQ 2 /* Real soft-irq */ +#define TRACE_EV_SOFT_IRQ_TASKLET_ACTION 3 /* Tasklet action */ +#define TRACE_EV_SOFT_IRQ_TASKLET_HI_ACTION 4 /* Tasklet hi-action */ +typedef struct _trace_soft_irq +{ + uint8_t event_sub_id; /* Soft-irq event Id */ + uint32_t event_data; /* Data associated with event */ +} trace_soft_irq; +#define TRACE_SOFT_IRQ(ID, DATA) \ + do \ + {\ + trace_soft_irq soft_irq_event;\ + soft_irq_event.event_sub_id = ID;\ + soft_irq_event.event_data = DATA;\ + trace_event(TRACE_EV_SOFT_IRQ, &soft_irq_event);\ + } while(0); + +/* TRACE_PROCESS */ +#define TRACE_EV_PROCESS_KTHREAD 1 /* Creation of a kernel thread */ +#define TRACE_EV_PROCESS_FORK 2 /* A fork or clone occured */ +#define TRACE_EV_PROCESS_EXIT 3 /* An exit occured */ +#define TRACE_EV_PROCESS_WAIT 4 /* A wait occured */ +#define TRACE_EV_PROCESS_SIGNAL 5 /* A signal has been sent */ +#define TRACE_EV_PROCESS_WAKEUP 6 /* Wake up a process */ +typedef struct _trace_process +{ + uint8_t event_sub_id; /* Process event ID */ + uint32_t event_data1; /* Data associated with event */ + uint32_t event_data2; +} trace_process; +#define TRACE_PROCESS(ID, DATA1, DATA2) \ + do \ + {\ + trace_process proc_event;\ + proc_event.event_sub_id = ID;\ + proc_event.event_data1 = DATA1;\ + proc_event.event_data2 = DATA2;\ + trace_event(TRACE_EV_PROCESS, &proc_event);\ + } while(0); + +/* TRACE_FILE_SYSTEM */ +#define TRACE_EV_FILE_SYSTEM_BUF_WAIT_START 1 /* Starting to wait for a data buffer */ +#define TRACE_EV_FILE_SYSTEM_BUF_WAIT_END 2 /* End to wait for a data buffer */ +#define TRACE_EV_FILE_SYSTEM_EXEC 3 /* An exec occured */ +#define TRACE_EV_FILE_SYSTEM_OPEN 4 /* An open occured */ +#define TRACE_EV_FILE_SYSTEM_CLOSE 5 /* A close occured */ +#define TRACE_EV_FILE_SYSTEM_READ 6 /* A read occured */ +#define TRACE_EV_FILE_SYSTEM_WRITE 7 /* A write occured */ +#define TRACE_EV_FILE_SYSTEM_SEEK 8 /* A seek occured */ +#define TRACE_EV_FILE_SYSTEM_IOCTL 9 /* An ioctl occured */ +#define TRACE_EV_FILE_SYSTEM_SELECT 10 /* A select occured */ +#define TRACE_EV_FILE_SYSTEM_POLL 11 /* A poll occured */ +typedef struct _trace_file_system +{ + uint8_t event_sub_id; /* File system event ID */ + uint32_t event_data1; /* Event data */ + uint32_t event_data2; /* Event data 2 */ + char* file_name; /* Name of file operated on */ +} trace_file_system; +#define TRACE_FILE_SYSTEM(ID, DATA1, DATA2, FILE_NAME) \ + do \ + {\ + trace_file_system fs_event;\ + fs_event.event_sub_id = ID;\ + fs_event.event_data1 = DATA1;\ + fs_event.event_data2 = DATA2;\ + fs_event.file_name = (char*)FILE_NAME;\ + trace_event(TRACE_EV_FILE_SYSTEM, &fs_event);\ + } while(0); + +/* TRACE_TIMER */ +#define TRACE_EV_TIMER_EXPIRED 1 /* Timer expired */ +#define TRACE_EV_TIMER_SETITIMER 2 /* Setting itimer occurred */ +#define TRACE_EV_TIMER_SETTIMEOUT 3 /* Setting sched timeout occurred */ +typedef struct _trace_timer +{ + uint8_t event_sub_id; /* Timer event ID */ + uint8_t event_sdata; /* Short data */ + uint32_t event_data1; /* Data associated with event */ + uint32_t event_data2; +} trace_timer; +#define TRACE_TIMER(ID, SDATA, DATA1, DATA2) \ + do \ + {\ + trace_timer timer_event;\ + timer_event.event_sub_id = ID;\ + timer_event.event_sdata = SDATA;\ + timer_event.event_data1 = DATA1;\ + timer_event.event_data2 = DATA2;\ + trace_event(TRACE_EV_TIMER, &timer_event);\ + } while(0); + +/* TRACE_MEMORY */ +#define TRACE_EV_MEMORY_PAGE_ALLOC 1 /* Allocating pages */ +#define TRACE_EV_MEMORY_PAGE_FREE 2 /* Freing pages */ +#define TRACE_EV_MEMORY_SWAP_IN 3 /* Swaping pages in */ +#define TRACE_EV_MEMORY_SWAP_OUT 4 /* Swaping pages out */ +#define TRACE_EV_MEMORY_PAGE_WAIT_START 5 /* Start to wait for page */ +#define TRACE_EV_MEMORY_PAGE_WAIT_END 6 /* End to wait for page */ +typedef struct _trace_memory +{ + uint8_t event_sub_id; /* Memory event ID */ + unsigned long event_data; /* Data associated with event */ +} trace_memory; +#define TRACE_MEMORY(ID, DATA) \ + do \ + {\ + trace_memory memory_event;\ + memory_event.event_sub_id = ID;\ + memory_event.event_data = DATA;\ + trace_event(TRACE_EV_MEMORY, &memory_event);\ + } while(0); + +/* TRACE_SOCKET */ +#define TRACE_EV_SOCKET_CALL 1 /* A socket call occured */ +#define TRACE_EV_SOCKET_CREATE 2 /* A socket has been created */ +#define TRACE_EV_SOCKET_SEND 3 /* Data was sent to a socket */ +#define TRACE_EV_SOCKET_RECEIVE 4 /* Data was read from a socket */ +typedef struct _trace_socket +{ + uint8_t event_sub_id; /* Socket event ID */ + uint32_t event_data1; /* Data associated with event */ + uint32_t event_data2; /* Data associated with event */ +} trace_socket; +#define TRACE_SOCKET(ID, DATA1, DATA2) \ + do \ + {\ + trace_socket socket_event;\ + socket_event.event_sub_id = ID;\ + socket_event.event_data1 = DATA1;\ + socket_event.event_data2 = DATA2;\ + trace_event(TRACE_EV_SOCKET, &socket_event);\ + } while(0); + +/* TRACE_IPC */ +#define TRACE_EV_IPC_CALL 1 /* A System V IPC call occured */ +#define TRACE_EV_IPC_MSG_CREATE 2 /* A message queue has been created */ +#define TRACE_EV_IPC_SEM_CREATE 3 /* A semaphore was created */ +#define TRACE_EV_IPC_SHM_CREATE 4 /* A shared memory segment has been created */ +typedef struct _trace_ipc +{ + uint8_t event_sub_id; /* IPC event ID */ + uint32_t event_data1; /* Data associated with event */ + uint32_t event_data2; /* Data associated with event */ +} trace_ipc; +#define TRACE_IPC(ID, DATA1, DATA2) \ + do \ + {\ + trace_ipc ipc_event;\ + ipc_event.event_sub_id = ID;\ + ipc_event.event_data1 = DATA1;\ + ipc_event.event_data2 = DATA2;\ + trace_event(TRACE_EV_IPC, &ipc_event);\ + } while(0); + +/* TRACE_NETWORK */ +#define TRACE_EV_NETWORK_PACKET_IN 1 /* A packet came in */ +#define TRACE_EV_NETWORK_PACKET_OUT 2 /* A packet was sent */ +typedef struct _trace_network +{ + uint8_t event_sub_id; /* Network event ID */ + uint32_t event_data; /* Event data */ +} trace_network; +#define TRACE_NETWORK(ID, DATA) \ + do \ + {\ + trace_network net_event;\ + net_event.event_sub_id = ID;\ + net_event.event_data = DATA;\ + trace_event(TRACE_EV_NETWORK, &net_event);\ + } while(0); + +/* Custom declared events */ +/* ***WARNING*** These structures should never be used as is, use the provided custom event creation + and logging functions. */ +typedef struct _trace_new_event +{ + uint32_t id; /* Custom event ID */ + char type[CUSTOM_EVENT_TYPE_STR_LEN]; /* Event type description */ + char desc[CUSTOM_EVENT_DESC_STR_LEN]; /* Detailed event description */ + uint32_t has_strings; /* Does the event description has strings */ + uint32_t data_size; /* Size of event data, if fixed */ + uint32_t desc_size; /* Size of the event description table */ + event_data_desc* data_description; /* Event data description table */ +} trace_new_event; +typedef struct _trace_custom +{ + uint32_t id; /* Event ID */ + uint32_t data_size; /* Size of data recorded by event */ + void* data; /* Data recorded by event */ +} trace_custom; + +#else /* Kernel is configured without tracing */ +#define TRACE_EVENT(ID, DATA) +#define TRACE_TRAP_ENTRY(ID, EIP) +#define TRACE_IRQ_ENTRY(ID, KERNEL) +#define TRACE_SCHEDCHANGE(OUT, IN, OUT_STATE) +#define TRACE_SOFT_IRQ(ID, DATA) +#define TRACE_PROCESS(ID, DATA1, DATA2) +#define TRACE_FILE_SYSTEM(ID, DATA1, DATA2, FILE_NAME) +#define TRACE_TIMER(ID, SDATA, DATA1, DATA2) +#define TRACE_MEMORY(ID, DATA) +#define TRACE_SOCKET(ID, DATA1, DATA2) +#define TRACE_IPC(ID, DATA1, DATA2) +#define TRACE_NETWORK(ID, DATA) +#endif /* defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE) */ + +#endif /* _LINUX_TRACE_H */ diff -urP linux-2.2.18/init/main.c linux-2.2.18-ltt-0.9.4/init/main.c --- linux-2.2.18/init/main.c Sun Dec 10 19:49:44 2000 +++ linux-2.2.18-ltt-0.9.4/init/main.c Mon Mar 19 15:59:23 2001 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -409,6 +410,14 @@ extern int agp_init (void); #endif +#if defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE) +extern void trace_init(void); +#endif + +#if defined(CONFIG_TRACE) +extern void tracer_setup(void); +#endif + /* * Boot command-line arguments */ @@ -1450,6 +1459,9 @@ #if defined(CONFIG_QUOTA) dquot_init_hash(); #endif +#if defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE) + trace_init(); +#endif check_bugs(); printk("POSIX conformance testing by UNIFIX\n"); @@ -1597,6 +1609,11 @@ real_root_mountflags = root_mountflags; if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY; else mount_initrd =0; +#endif + +#ifdef CONFIG_TRACE + /* Setup the tracer */ + tracer_setup(); #endif /* Set up devices .. */ diff -urP linux-2.2.18/ipc/msg.c linux-2.2.18-ltt-0.9.4/ipc/msg.c --- linux-2.2.18/ipc/msg.c Tue Jan 4 13:12:25 2000 +++ linux-2.2.18-ltt-0.9.4/ipc/msg.c Mon Mar 19 15:59:23 2001 @@ -16,6 +16,8 @@ #include #include +#include + #include extern int ipcperms (struct ipc_perm *ipcp, short msgflg); @@ -333,6 +335,7 @@ ret = (unsigned int) msq->msg_perm.seq * MSGMNI + id; } unlock_kernel(); + TRACE_IPC(TRACE_EV_IPC_MSG_CREATE, ret, msgflg); return ret; } diff -urP linux-2.2.18/ipc/sem.c linux-2.2.18-ltt-0.9.4/ipc/sem.c --- linux-2.2.18/ipc/sem.c Wed May 3 20:16:53 2000 +++ linux-2.2.18-ltt-0.9.4/ipc/sem.c Mon Mar 19 15:59:23 2001 @@ -54,6 +54,8 @@ #include #include +#include + #include extern int ipcperms (struct ipc_perm *ipcp, short semflg); @@ -171,6 +173,7 @@ } out: unlock_kernel(); + TRACE_IPC(TRACE_EV_IPC_SEM_CREATE, err, semflg); return err; } diff -urP linux-2.2.18/ipc/shm.c linux-2.2.18-ltt-0.9.4/ipc/shm.c --- linux-2.2.18/ipc/shm.c Wed Jun 7 17:26:44 2000 +++ linux-2.2.18-ltt-0.9.4/ipc/shm.c Mon Mar 19 15:59:23 2001 @@ -14,6 +14,8 @@ #include #include +#include + #include #include @@ -169,6 +171,7 @@ } unlock_kernel(); up(¤t->mm->mmap_sem); + TRACE_IPC(TRACE_EV_IPC_SHM_CREATE, err, shmflg); return err; } diff -urP linux-2.2.18/kernel/Makefile linux-2.2.18-ltt-0.9.4/kernel/Makefile --- linux-2.2.18/kernel/Makefile Wed May 6 14:01:46 1998 +++ linux-2.2.18-ltt-0.9.4/kernel/Makefile Mon Mar 19 15:59:23 2001 @@ -25,6 +25,10 @@ OX_OBJS += ksyms.o endif +ifdef CONFIG_TRACE +OX_OBJS += trace.o +endif + CFLAGS_sched.o := $(PROFILING) -fno-omit-frame-pointer include $(TOPDIR)/Rules.make diff -urP linux-2.2.18/kernel/exit.c linux-2.2.18-ltt-0.9.4/kernel/exit.c --- linux-2.2.18/kernel/exit.c Tue Jan 4 13:12:25 2000 +++ linux-2.2.18-ltt-0.9.4/kernel/exit.c Mon Mar 19 15:59:23 2001 @@ -14,6 +14,8 @@ #include #endif +#include + #include #include #include @@ -385,6 +387,8 @@ del_timer(&tsk->real_timer); end_bh_atomic(); + TRACE_PROCESS(TRACE_EV_PROCESS_EXIT, 0, 0); + lock_kernel(); fake_volatile: #ifdef CONFIG_BSD_PROCESS_ACCT @@ -439,6 +443,8 @@ if (options & ~(WNOHANG|WUNTRACED|__WCLONE)) return -EINVAL; + + TRACE_PROCESS(TRACE_EV_PROCESS_WAIT, pid, 0); add_wait_queue(¤t->wait_chldexit,&wait); repeat: diff -urP linux-2.2.18/kernel/fork.c linux-2.2.18-ltt-0.9.4/kernel/fork.c --- linux-2.2.18/kernel/fork.c Tue Oct 26 20:53:42 1999 +++ linux-2.2.18-ltt-0.9.4/kernel/fork.c Mon Mar 19 15:59:23 2001 @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -716,6 +718,10 @@ p->next_run = NULL; p->prev_run = NULL; + + /* Trace the event */ + TRACE_PROCESS(TRACE_EV_PROCESS_FORK, retval, 0); + wake_up_process(p); /* do this last */ } ++total_forks; diff -urP linux-2.2.18/kernel/itimer.c linux-2.2.18-ltt-0.9.4/kernel/itimer.c --- linux-2.2.18/kernel/itimer.c Tue Nov 24 16:51:44 1998 +++ linux-2.2.18-ltt-0.9.4/kernel/itimer.c Mon Mar 19 15:59:23 2001 @@ -10,6 +10,8 @@ #include #include +#include + #include /* @@ -94,6 +96,7 @@ struct task_struct * p = (struct task_struct *) __data; unsigned long interval; + TRACE_TIMER(TRACE_EV_TIMER_EXPIRED, 0, 0, 0); send_sig(SIGALRM, p, 1); interval = p->it_real_incr; if (interval) { @@ -113,6 +116,7 @@ j = tvtojiffies(&value->it_value); if (ovalue && (k = do_getitimer(which, ovalue)) < 0) return k; + TRACE_TIMER(TRACE_EV_TIMER_SETITIMER, which, i, j); switch (which) { case ITIMER_REAL: start_bh_atomic(); diff -urP linux-2.2.18/kernel/sched.c linux-2.2.18-ltt-0.9.4/kernel/sched.c --- linux-2.2.18/kernel/sched.c Sun Dec 10 19:49:44 2000 +++ linux-2.2.18-ltt-0.9.4/kernel/sched.c Mon Mar 19 15:59:23 2001 @@ -32,6 +32,8 @@ #include #include +#include + #include #include #include @@ -445,6 +447,8 @@ { unsigned long flags; + TRACE_PROCESS(TRACE_EV_PROCESS_WAKEUP, p->pid, p->state); + /* * We want the common case fall through straight, thus the goto. */ @@ -465,6 +469,7 @@ { struct task_struct * p = (struct task_struct *) __data; + TRACE_TIMER(TRACE_EV_TIMER_EXPIRED, 0, 0, 0); wake_up_process(p); } @@ -642,6 +647,8 @@ } } + TRACE_TIMER(TRACE_EV_TIMER_SETTIMEOUT, 0, timeout, 0); + expire = timeout + jiffies; init_timer(&timer); @@ -828,6 +835,7 @@ kstat.context_swtch++; get_mmu_context(next); + TRACE_SCHEDCHANGE(prev->pid, next->pid, prev->state); switch_to(prev, next, prev); __schedule_tail(prev); @@ -1540,6 +1548,7 @@ static void timer_bh(void) { + TRACE_EVENT(TRACE_EV_KERNEL_TIMER, NULL); update_times(); run_old_timers(); run_timer_list(); diff -urP linux-2.2.18/kernel/signal.c linux-2.2.18-ltt-0.9.4/kernel/signal.c --- linux-2.2.18/kernel/signal.c Wed May 3 20:16:53 2000 +++ linux-2.2.18-ltt-0.9.4/kernel/signal.c Mon Mar 19 15:59:23 2001 @@ -13,6 +13,8 @@ #include #include +#include + #include /* @@ -281,6 +283,8 @@ spin_unlock_irqrestore(&t->sigmask_lock, flags); goto out_nolock; } + + TRACE_PROCESS(TRACE_EV_PROCESS_SIGNAL, sig, t->pid); switch (sig) { case SIGKILL: case SIGCONT: diff -urP linux-2.2.18/kernel/softirq.c linux-2.2.18-ltt-0.9.4/kernel/softirq.c --- linux-2.2.18/kernel/softirq.c Sun Mar 21 10:22:00 1999 +++ linux-2.2.18-ltt-0.9.4/kernel/softirq.c Mon Mar 19 15:59:23 2001 @@ -16,6 +16,8 @@ #include #include +#include + #include /* intr_count died a painless death... -DaveM */ @@ -47,8 +49,10 @@ clear_active_bhs(active); bh = bh_base; do { - if (active & 1) + if (active & 1){ + TRACE_SOFT_IRQ(TRACE_EV_SOFT_IRQ_BOTTOM_HALF, ((bh-bh_base))); (*bh)(); + } bh++; active >>= 1; } while (active); diff -urP linux-2.2.18/kernel/trace.c linux-2.2.18-ltt-0.9.4/kernel/trace.c --- linux-2.2.18/kernel/trace.c Wed Dec 31 19:00:00 1969 +++ linux-2.2.18-ltt-0.9.4/kernel/trace.c Mon Mar 19 15:59:23 2001 @@ -0,0 +1,624 @@ +/* + * linux/kernel/trace.c + * + * (C) Copyright 1999, 2000 - Karim Yaghmour (karym@opersys.com) + * + * This code is distributed under the GPL license + * + * Tracing management + * + */ + +#include /* For __init */ +#include /* Tracing definitions */ +#include /* Miscellaneous error codes */ +#include /* NULL */ +#include /* kmalloc() */ +#include /* EXPORT_SYMBOL */ + +/* Local variables */ +static int tracer_registered = 0; /* Is there a tracer registered */ +struct tracer * tracer = NULL; /* The registered tracer */ + +/* Trace callback table entry */ +struct trace_callback_table_entry +{ + tracer_call Callback; /* The callback function */ + + struct trace_callback_table_entry* Next; /* Next entry */ +}; + +/* Trace callback table */ +struct trace_callback_table_entry trace_callback_table[TRACE_EV_MAX]; + +/* Custom event description */ +struct custom_event_desc +{ + /* The event itself */ + trace_new_event Event; + + /* List links */ + struct custom_event_desc* Next; + struct custom_event_desc* Prev; +}; + +/* Next event ID to be used */ +int next_event_id; + +/* Circular list of custom events */ +struct custom_event_desc custom_events_head; +struct custom_event_desc* custom_events; + +/* Circular list lock */ +rwlock_t custom_list_lock = RW_LOCK_UNLOCKED; + +/**************************************************** + * Register the tracer to the kernel + * Return values : + * 0, all is OK + * -EBUSY, there already is a registered tracer + * -ENOMEM, couldn't allocate memory + ****************************************************/ +int register_tracer(tracer_call pmTraceFunction) +{ + /* Is there a tracer already registered */ + if(tracer_registered == 1) + return -EBUSY; + + /* Allocate memory for the tracer */ + if((tracer = (struct tracer *) kmalloc(sizeof(struct tracer), GFP_KERNEL)) == NULL) + /* We couldn't allocate any memory */ + return -ENOMEM; + + /* There is a tracer registered */ + tracer_registered = 1; + + /* Set the tracer to the one being passed by the caller */ + tracer->trace = pmTraceFunction; + + /* Initialize the tracer settings */ + tracer->fetch_syscall_eip_use_bounds = 0; + tracer->fetch_syscall_eip_use_depth = 0; + + /* Tell the caller that everything went fine */ + return 0; +} + +/*************************************************** + * Unregister the currently registered tracer + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer + * -ENXIO, unregestering wrong tracer + ***************************************************/ +int unregister_tracer(tracer_call pmTraceFunction) +{ + /* Is there a tracer already registered */ + if(tracer_registered == 0) + /* Nothing to unregister */ + return -ENOMEDIUM; + + /* Is it the tracer that was registered */ + if(tracer->trace == pmTraceFunction) + /* There isn't any tracer in here */ + tracer_registered = 0; + else + return -ENXIO; + + /* Free the memory used by the tracing structure */ + kfree(tracer); + tracer = NULL; + + /* Tell the caller that everything went OK */ + return 0; +} + +/******************************************************* + * Set the tracing configuration + * Parameters : + * pmTraceFunction, the trace function. + * pmFetchSyscallUseDepth, Use depth to fetch eip + * pmFetchSyscallUseBounds, Use bounds to fetch eip + * pmSyscallEipDepth, Detph to fetch eip + * pmSyscallLowerBound, Lower bound eip address + * pmSyscallUpperBound, Upper bound eip address + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer + * -ENXIO, wrong tracer + * -EINVAL, invalid configuration + *******************************************************/ +int trace_set_config(tracer_call pmTraceFunction, + int pmFetchSyscallUseDepth, + int pmFetchSyscallUseBounds, + int pmSyscallEipDepth, + void* pmSyscallLowerBound, + void* pmSyscallUpperBound) +{ + /* Is there a tracer already registered */ + if(tracer_registered == 0) + return -ENOMEDIUM; + + /* Is it the tracer that was registered */ + if(tracer->trace != pmTraceFunction) + return -ENXIO; + + /* Is this a valid configuration */ + if((pmFetchSyscallUseDepth && pmFetchSyscallUseBounds) + ||(pmSyscallLowerBound > pmSyscallUpperBound) + ||(pmSyscallEipDepth < 0)) + return -EINVAL; + + /* Set the configuration */ + tracer->fetch_syscall_eip_use_depth = pmFetchSyscallUseDepth; + tracer->fetch_syscall_eip_use_bounds = pmFetchSyscallUseBounds; + tracer->syscall_eip_depth = pmSyscallEipDepth; + tracer->syscall_lower_eip_bound = pmSyscallLowerBound; + tracer->syscall_upper_eip_bound = pmSyscallUpperBound; + + /* Tell the caller that everything was OK */ + return 0; +} + +/******************************************************* + * Get the tracing configuration + * Parameters : + * pmFetchSyscallUseDepth, Use depth to fetch eip + * pmFetchSyscallUseBounds, Use bounds to fetch eip + * pmSyscallEipDepth, Detph to fetch eip + * pmSyscallLowerBound, Lower bound eip address + * pmSyscallUpperBound, Upper bound eip address + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer + *******************************************************/ +int trace_get_config(int* pmFetchSyscallUseDepth, + int* pmFetchSyscallUseBounds, + int* pmSyscallEipDepth, + void** pmSyscallLowerBound, + void** pmSyscallUpperBound) +{ + /* Is there a tracer already registered */ + if(tracer_registered == 0) + return -ENOMEDIUM; + + /* Get the configuration */ + *pmFetchSyscallUseDepth = tracer->fetch_syscall_eip_use_depth; + *pmFetchSyscallUseBounds = tracer->fetch_syscall_eip_use_bounds; + *pmSyscallEipDepth = tracer->syscall_eip_depth; + *pmSyscallLowerBound = tracer->syscall_lower_eip_bound; + *pmSyscallUpperBound = tracer->syscall_upper_eip_bound; + + /* Tell the caller that everything was OK */ + return 0; +} + +/******************************************************* + * Register a callback function to be called on occurence + * of given event + * Parameters : + * pmTraceFunction, the callback function. + * pmEventID, the event ID to be monitored. + * Return values : + * 0, all is OK + * -ENOMEM, unable to allocate memory for callback + *******************************************************/ +int trace_register_callback(tracer_call pmTraceFunction, + uint8_t pmEventID) +{ + struct trace_callback_table_entry* pTCTEntry; + + /* Search for an empty entry in the callback table */ + for(pTCTEntry = &(trace_callback_table[pmEventID - 1]); + pTCTEntry->Next != NULL; + pTCTEntry = pTCTEntry->Next); + + /* Allocate a new callback */ + if((pTCTEntry->Next = kmalloc(sizeof(struct trace_callback_table_entry), GFP_ATOMIC)) == NULL) + return -ENOMEM; + + /* Setup the new callback */ + pTCTEntry->Next->Callback = pmTraceFunction; + pTCTEntry->Next->Next = NULL; + + /* Tell the caller everything is ok */ + return 0; +} + +/******************************************************* + * UnRegister a callback function. + * Parameters : + * pmTraceFunction, the callback function. + * pmEventID, the event ID that had to be monitored. + * Return values : + * 0, all is OK + * -ENOMEDIUM, no such callback resigtered + *******************************************************/ +int trace_unregister_callback(tracer_call pmTraceFunction, + uint8_t pmEventID) +{ + struct trace_callback_table_entry* pTCTEntry; /* Pointer to trace callback table entry */ + struct trace_callback_table_entry* pTempEntry; /* Pointer to trace callback table entry */ + + /* Search for the callback in the callback table */ + for(pTCTEntry = &(trace_callback_table[pmEventID - 1]); + ((pTCTEntry->Next != NULL) && (pTCTEntry->Next->Callback != pmTraceFunction)); + pTCTEntry = pTCTEntry->Next); + + /* Did we find anything */ + if(pTCTEntry == NULL) + return -ENOMEDIUM; + + /* Free the callback entry */ + pTempEntry = pTCTEntry->Next->Next; + kfree(pTCTEntry->Next); + pTCTEntry->Next = pTempEntry; + + /* Tell the caller everything is ok */ + return 0; +} + +/******************************************************* + * Create a new traceable event type + * Parameters : + * pmEventType, string describing event type + * pmEventDesc, string used to print out details + * pmEventDataDescTable, Table containing information + * about each data describing the + * event. + * Return values : + * New Event ID if all is OK + * -ENOMEM, Unable to allocate new event + *******************************************************/ +int trace_create_event(char* pmEventType, + char* pmEventDesc, + event_data_desc* pmEventDataDescTable) +{ + int i; /* Generic index */ + int lDescTableSize = 0; /* Size of data description table */ + struct custom_event_desc* pNewEvent; /* Newly created event */ + + /* Create event */ + if((pNewEvent = (struct custom_event_desc*) kmalloc(sizeof(struct custom_event_desc), GFP_ATOMIC)) == NULL) + return -ENOMEM; + + /* Set basic event properties */ + if(pmEventType != NULL) + strncpy(pNewEvent->Event.type, pmEventType, CUSTOM_EVENT_TYPE_STR_LEN); + else + pNewEvent->Event.type[0] = '\0'; + if(pmEventDesc != NULL) + strncpy(pNewEvent->Event.desc, pmEventDesc, CUSTOM_EVENT_DESC_STR_LEN); + else + pNewEvent->Event.desc[0] = '\0'; + pNewEvent->Event.has_strings = 0; + + /* Ensure that strings are bound */ + pNewEvent->Event.type[CUSTOM_EVENT_TYPE_STR_LEN - 1] = '\0'; + pNewEvent->Event.type[CUSTOM_EVENT_DESC_STR_LEN - 1] = '\0'; + + /* Is there a event data description table */ + if(pmEventDataDescTable != NULL) + { + /* Go through description table */ + for(i = 0; + (pmEventDataDescTable[i].notfixed != 0) || + (pmEventDataDescTable[i].length != 0); + i++) + { + /* Is this data type of fixed length */ + if(pmEventDataDescTable[i].notfixed == 1) + pNewEvent->Event.has_strings = 1; + + /* Update the data size */ + pNewEvent->Event.data_size += pmEventDataDescTable[i].length; + + /* Update data description table size */ + lDescTableSize += sizeof(event_data_desc); + } + + /* Add the size of the terminating entry */ + lDescTableSize += sizeof(event_data_desc); + + /* Set data description size */ + pNewEvent->Event.desc_size = lDescTableSize; + + /* Create space to hold data description table */ + if((pNewEvent->Event.data_description = (event_data_desc*) kmalloc(lDescTableSize, GFP_ATOMIC)) == NULL) + { + /* Free the already allocated space and return an error */ + kfree(pNewEvent); + return -ENOMEM; + } + + /* Copy event description table */ + memcpy(pNewEvent->Event.data_description, pmEventDataDescTable, lDescTableSize); + } + else + { + /* There is no custom data provided with this event */ + pNewEvent->Event.has_strings = 0; + pNewEvent->Event.data_size = 0; + pNewEvent->Event.desc_size = 0; + pNewEvent->Event.data_description = NULL; + } + + /* Give the new event a unique event ID */ + pNewEvent->Event.id = next_event_id; + next_event_id++; + + /* Insert new event in event list */ + write_lock(&custom_list_lock); + pNewEvent->Next = custom_events; + pNewEvent->Prev = custom_events->Prev; + custom_events->Prev->Next = pNewEvent; + custom_events->Prev = pNewEvent; + write_unlock(&custom_list_lock); + + /* Log the event creation event */ + trace_event(TRACE_EV_NEW_EVENT, &(pNewEvent->Event)); + + /* Return new event ID */ + return pNewEvent->Event.id; +} + +/******************************************************* + * Destroy a created event type + * Parameters : + * pmEventID, the Id returned by trace_create_event() + * Return values : + * NONE + *******************************************************/ +void trace_destroy_event(int pmEventID) +{ + struct custom_event_desc* pEventDesc; /* Generic event description pointer */ + + /* Lock the table for writting */ + write_lock(&custom_list_lock); + + /* Go through the event description list */ + for(pEventDesc = custom_events->Next; + pEventDesc != custom_events; + pEventDesc = pEventDesc->Next) + if(pEventDesc->Event.id == pmEventID) + break; + + /* If we found something */ + if(pEventDesc != custom_events) + { + /* Remove the event fromt the list */ + pEventDesc->Next->Prev = pEventDesc->Prev; + pEventDesc->Prev->Next = pEventDesc->Next; + + /* Free the memory used by this event */ + kfree(pEventDesc->Event.data_description); + kfree(pEventDesc); + } + + /* Unlock the table for writting */ + write_unlock(&custom_list_lock); +} + +/******************************************************* + * Relog the declarations of custom events. This is + * necessary to make sure that even though the event + * creation might not have taken place during a trace, + * that all custom events be part of all traces. Hence, + * if a custom event occurs during a trace, we can be + * sure that it's definition is part of the trace. + * Parameters : + * NONE + * Return values : + * NONE + *******************************************************/ +void trace_reregister_custom_events(void) +{ + struct custom_event_desc* pEventDesc; /* Generic event description pointer */ + + /* Lock the table for reading */ + read_lock(&custom_list_lock); + + /* Go through the event description list */ + for(pEventDesc = custom_events->Next; + pEventDesc != custom_events; + pEventDesc = pEventDesc->Next) + /* Log the event creation event */ + trace_event(TRACE_EV_NEW_EVENT, &(pEventDesc->Event)); + + /* Unlock the table for reading */ + read_unlock(&custom_list_lock); +} + +/******************************************************* + * Trace a formatted event + * Parameters : + * pmEventID, the event Id provided upon creation + * ..., printf-like data that will be used to fill the + * event string. + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer or this + * event doesn't exist. + * -EBUSY, tracing hasn't started yet + *******************************************************/ +int trace_formatted_event(int pmEventID, ...) +{ + int lStringSize; /* Size of the string outputed by vsprintf() */ + char lString[CUSTOM_EVENT_FINAL_STR_LEN]; /* Final formatted string */ + va_list lVarArgList; /* Variable argument list */ + trace_custom lCustom; /* Custom event */ + struct custom_event_desc* pEventDesc; /* Generic event description pointer */ + + /* Lock the table for reading */ + read_lock(&custom_list_lock); + + /* Go through the event description list */ + for(pEventDesc = custom_events->Next; + pEventDesc != custom_events; + pEventDesc = pEventDesc->Next) + if(pEventDesc->Event.id == pmEventID) + break; + + /* If we haven't found anything */ + if(pEventDesc == custom_events) + { + /* Unlock the table for reading */ + read_unlock(&custom_list_lock); + + /* No such thing */ + return -ENOMEDIUM; + } + + /* Set custom event Id */ + lCustom.id = pmEventID; + + /* Initialize variable argument list access */ + va_start(lVarArgList, pmEventID); + + /* Print the description out to the temporary buffer */ + lStringSize = vsprintf(lString, pEventDesc->Event.desc, lVarArgList); + + /* Unlock the table for reading */ + read_unlock(&custom_list_lock); + + /* Facilitate return to caller */ + va_end(lVarArgList); + + /* Set the size of the event */ + lCustom.data_size = lStringSize + 1; + + /* Set the pointer to the event data */ + lCustom.data = lString; + + /* Log the custom event */ + return trace_event(TRACE_EV_CUSTOM, &lCustom); +} + +/******************************************************* + * Trace a raw event + * Parameters : + * pmEventID, the event Id provided upon creation + * pmEventSize, the size of the data provided + * pmEventData, data buffer describing event + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer or this + * event doesn't exist. + * -EBUSY, tracing hasn't started yet + *******************************************************/ +int trace_raw_event(int pmEventID, int pmEventSize, void* pmEventData) +{ + trace_custom lCustom; /* Custom event */ + struct custom_event_desc* pEventDesc; /* Generic event description pointer */ + + /* Lock the table for reading */ + read_lock(&custom_list_lock); + + /* Go through the event description list */ + for(pEventDesc = custom_events->Next; + pEventDesc != custom_events; + pEventDesc = pEventDesc->Next) + if(pEventDesc->Event.id == pmEventID) + break; + + /* Unlock the table for reading */ + read_unlock(&custom_list_lock); + + /* If we haven't found anything */ + if(pEventDesc == custom_events) + /* No such thing */ + return -ENOMEDIUM; + + /* Set custom event Id */ + lCustom.id = pmEventID; + + /* Set the data size */ + if(pmEventSize <= CUSTOM_EVENT_MAX_SIZE) + lCustom.data_size = pmEventSize; + else + lCustom.data_size = CUSTOM_EVENT_MAX_SIZE; + + /* Set the pointer to the event data */ + lCustom.data = pmEventData; + + /* Log the custom event */ + return trace_event(TRACE_EV_CUSTOM, &lCustom); +} + +/******************************************************* + * Trace an event + * Parameters : + * pmEventID, the event's ID (check out trace.h) + * pmEventStruct, the structure describing the event + * Return values : + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer + * -EBUSY, tracing hasn't started yet + *******************************************************/ +int trace_event(uint8_t pmEventID, + void* pmEventStruct) +{ + int lRetValue; /* The return value */ + struct trace_callback_table_entry* pTCTEntry; /* Pointer to trace callback table entry */ + + /* Is there a tracer registered */ + if(tracer_registered != 1) + lRetValue = -ENOMEDIUM; + else + /* Call the tracer */ + lRetValue = tracer->trace(pmEventID, pmEventStruct); + + /* Are there any callbacks to call */ + if(trace_callback_table[pmEventID - 1].Next != NULL) + { + /* Call all the callbacks linked to this event */ + for(pTCTEntry = trace_callback_table[pmEventID - 1].Next; + pTCTEntry != NULL; + pTCTEntry = pTCTEntry->Next) + pTCTEntry->Callback(pmEventID, pmEventStruct); + } + + /* Give the return value */ + return lRetValue; +} + +/******************************************************* + * Initialize trace facility + * Parameters : + * NONE + * Return values : + * NONE + *******************************************************/ +void __init trace_init(void) +{ + int i; /* Generic index */ + + /* Initialize callback table */ + for(i = 0; i < TRACE_EV_MAX; i++) + { + trace_callback_table[i].Callback = NULL; + trace_callback_table[i].Next = NULL; + } + + /* Next event ID to be used */ + next_event_id = TRACE_EV_MAX + 1; + + /* Initialize custom events list */ + custom_events = &custom_events_head; + custom_events->Next = custom_events; + custom_events->Prev = custom_events; +} + +/* Export symbols so that can be visible from outside this file */ +EXPORT_SYMBOL(register_tracer); +EXPORT_SYMBOL(unregister_tracer); +EXPORT_SYMBOL(trace_set_config); +EXPORT_SYMBOL(trace_get_config); +EXPORT_SYMBOL(trace_register_callback); +EXPORT_SYMBOL(trace_unregister_callback); +EXPORT_SYMBOL(trace_create_event); +EXPORT_SYMBOL(trace_destroy_event); +EXPORT_SYMBOL(trace_reregister_custom_events); +EXPORT_SYMBOL(trace_formatted_event); +EXPORT_SYMBOL(trace_raw_event); +EXPORT_SYMBOL(trace_event); diff -urP linux-2.2.18/mm/filemap.c linux-2.2.18-ltt-0.9.4/mm/filemap.c --- linux-2.2.18/mm/filemap.c Sun Dec 10 19:49:44 2000 +++ linux-2.2.18-ltt-0.9.4/mm/filemap.c Mon Mar 19 15:59:23 2001 @@ -22,6 +22,8 @@ #include #include +#include + #include #include @@ -361,12 +363,14 @@ add_wait_queue(&page->wait, &wait); repeat: tsk->state = TASK_UNINTERRUPTIBLE; + TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_WAIT_START, 0); sync_page(page); if (PageLocked(page)) { schedule(); goto repeat; } tsk->state = TASK_RUNNING; + TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_WAIT_END, 0); remove_wait_queue(&page->wait, &wait); } diff -urP linux-2.2.18/mm/page_alloc.c linux-2.2.18-ltt-0.9.4/mm/page_alloc.c --- linux-2.2.18/mm/page_alloc.c Mon Sep 4 13:39:28 2000 +++ linux-2.2.18-ltt-0.9.4/mm/page_alloc.c Mon Mar 19 15:59:23 2001 @@ -14,6 +14,8 @@ #include #include +#include + #include #include /* for copy_to/from_user */ #include @@ -100,6 +102,8 @@ unsigned long mask = (~0UL) << order; unsigned long flags; + TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_FREE, order); + spin_lock_irqsave(&page_alloc_lock, flags); #define list(x) (mem_map+(x)) @@ -198,6 +202,8 @@ } #endif + TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_ALLOC, order); + /* * If this is a recursive call, we'd better * do our best to just allocate things without @@ -414,6 +420,8 @@ vma->vm_mm->rss++; tsk->min_flt++; swap_free(entry); + + TRACE_MEMORY(TRACE_EV_MEMORY_SWAP_IN, page); if (!write_access || is_page_shared(page_map)) { set_pte(page_table, mk_pte(page, vma->vm_page_prot)); diff -urP linux-2.2.18/mm/vmscan.c linux-2.2.18-ltt-0.9.4/mm/vmscan.c --- linux-2.2.18/mm/vmscan.c Mon Sep 4 13:39:28 2000 +++ linux-2.2.18-ltt-0.9.4/mm/vmscan.c Mon Mar 19 15:59:23 2001 @@ -18,6 +18,8 @@ #include #include +#include + #include /* @@ -160,6 +162,8 @@ /* We checked we were unlocked way up above, and we have been careful not to stall until here */ set_bit(PG_locked, &page_map->flags); + + TRACE_MEMORY(TRACE_EV_MEMORY_SWAP_OUT, page); /* OK, do a physical asynchronous write to swap. */ rw_swap_page(WRITE, entry, (char *) page, 0); diff -urP linux-2.2.18/net/core/dev.c linux-2.2.18-ltt-0.9.4/net/core/dev.c --- linux-2.2.18/net/core/dev.c Sun Dec 10 19:49:44 2000 +++ linux-2.2.18-ltt-0.9.4/net/core/dev.c Mon Mar 19 15:59:23 2001 @@ -94,6 +94,9 @@ #ifdef CONFIG_NET_RADIO #include #endif /* CONFIG_NET_RADIO */ + +#include + #ifdef CONFIG_PLIP extern int plip_init(void); #endif @@ -596,6 +599,9 @@ NET_PROFILE_ENTER(dev_queue_xmit); #endif + /* Trace the event */ + TRACE_NETWORK(TRACE_EV_NETWORK_PACKET_OUT, skb->protocol); + start_bh_atomic(); q = dev->qdisc; if (q->enqueue) { @@ -912,6 +918,9 @@ * We have a packet. Therefore the queue has shrunk */ skb = skb_dequeue(&backlog); + + /* Trace this event */ + TRACE_NETWORK(TRACE_EV_NETWORK_PACKET_IN, skb->protocol); /* This can happen if dev_clear_backlog is running * at the same time and it empties the queue. diff -urP linux-2.2.18/net/socket.c linux-2.2.18-ltt-0.9.4/net/socket.c --- linux-2.2.18/net/socket.c Sun Dec 10 19:49:44 2000 +++ linux-2.2.18-ltt-0.9.4/net/socket.c Mon Mar 19 15:59:23 2001 @@ -73,6 +73,8 @@ #include #endif +#include + #include #include @@ -327,6 +329,8 @@ int err; struct scm_cookie scm; + TRACE_SOCKET(TRACE_EV_SOCKET_SEND, sock->type, size); + err = scm_send(sock, msg, &scm); if (err >= 0) { err = sock->ops->sendmsg(sock, msg, size, &scm); @@ -341,6 +345,8 @@ memset(&scm, 0, sizeof(scm)); + TRACE_SOCKET(TRACE_EV_SOCKET_RECEIVE, sock->type, size); + size = sock->ops->recvmsg(sock, msg, size, flags, &scm); if (size >= 0) scm_recv(sock, msg, &scm, flags); @@ -654,6 +660,8 @@ goto out_release; sock->file = fcheck(retval); + TRACE_SOCKET(TRACE_EV_SOCKET_CREATE, retval, type); + out: unlock_kernel(); return retval; @@ -1330,6 +1338,7 @@ a0=a[0]; a1=a[1]; + TRACE_SOCKET(TRACE_EV_SOCKET_CALL, call, a0); switch(call) { case SYS_SOCKET: