diff -urpN linux-2.6.10-relayfs/arch/arm/kernel/entry-common.S linux-2.6.10-relayfs-ltt/arch/arm/kernel/entry-common.S --- linux-2.6.10-relayfs/arch/arm/kernel/entry-common.S 2004-12-24 16:33:49.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/arm/kernel/entry-common.S 2005-01-13 22:21:44.000000000 -0500 @@ -29,6 +29,11 @@ * stack. */ ret_fast_syscall: +#if (CONFIG_LTT) + mov r7, r0 @ save returned r0 + bl trace_real_syscall_exit + mov r0, r7 +#endif disable_irq r1 @ disable interrupts ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK @@ -126,6 +131,16 @@ ENTRY(vector_swi) mcr p15, 0, ip, c1, c0 @ update control register #endif enable_irq ip +#if (CONFIG_LTT) + /* zzz note that validity of scno is not yet checked. + * zzz The visualizer checks it. + */ + add r1, sp, #S_R0 @ pointer to regs + mov r0, scno @ syscall number + bl trace_real_syscall_entry + add r1, sp, #S_R0 @ pointer to regs + ldmia r1, {r0 - r3} @ have to reload r0 - r3 +#endif str r4, [sp, #-S_OFF]! @ push fifth arg @@ -166,6 +181,9 @@ __sys_trace: __sys_trace_return: str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 +#if (CONFIG_LTT) + bl trace_real_syscall_exit +#endif mov r1, sp mov r0, #1 @ trace exit [IP = 1] bl syscall_trace diff -urpN linux-2.6.10-relayfs/arch/arm/kernel/irq.c linux-2.6.10-relayfs-ltt/arch/arm/kernel/irq.c --- linux-2.6.10-relayfs/arch/arm/kernel/irq.c 2004-12-24 16:33:47.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/arm/kernel/irq.c 2005-01-13 22:21:44.000000000 -0500 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -486,6 +487,8 @@ asmlinkage void asm_do_IRQ(unsigned int { struct irqdesc *desc = irq_desc + irq; + ltt_ev_irq_entry(irq, !(user_mode(regs))); + /* * Some hardware gives randomly wrong interrupts. Rather * than crashing, do something sensible. @@ -505,6 +508,8 @@ asmlinkage void asm_do_IRQ(unsigned int spin_unlock(&irq_controller_lock); irq_exit(); + + ltt_ev_irq_exit(); } void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained) diff -urpN linux-2.6.10-relayfs/arch/arm/kernel/process.c linux-2.6.10-relayfs-ltt/arch/arm/kernel/process.c --- linux-2.6.10-relayfs/arch/arm/kernel/process.c 2004-12-24 16:35:28.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/arm/kernel/process.c 2005-01-13 23:49:42.000000000 -0500 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -421,6 +422,7 @@ asm( ".section .text\n" pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { struct pt_regs regs; + long pid; memset(®s, 0, sizeof(regs)); @@ -430,7 +432,12 @@ pid_t kernel_thread(int (*fn)(void *), v regs.ARM_pc = (unsigned long)kernel_thread_helper; regs.ARM_cpsr = SVC_MODE; - return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + pid = do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); +#if (CONFIG_LTT) + if(pid >= 0) + ltt_ev_process(LTT_EV_PROCESS_KTHREAD, pid, (int) fn); +#endif + return pid; } EXPORT_SYMBOL(kernel_thread); diff -urpN linux-2.6.10-relayfs/arch/arm/kernel/sys_arm.c linux-2.6.10-relayfs-ltt/arch/arm/kernel/sys_arm.c --- linux-2.6.10-relayfs/arch/arm/kernel/sys_arm.c 2004-12-24 16:34:26.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/arm/kernel/sys_arm.c 2005-01-13 22:21:44.000000000 -0500 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -167,6 +168,8 @@ asmlinkage int sys_ipc(uint call, int fi version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; + ltt_ev_ipc(LTT_EV_IPC_CALL, call, first); + switch (call) { case SEMOP: return sys_semop(first, (struct sembuf __user *)ptr, second); diff -urpN linux-2.6.10-relayfs/arch/arm/kernel/traps.c linux-2.6.10-relayfs-ltt/arch/arm/kernel/traps.c --- linux-2.6.10-relayfs/arch/arm/kernel/traps.c 2004-12-24 16:34:32.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/arm/kernel/traps.c 2005-01-13 23:50:36.000000000 -0500 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -200,6 +201,69 @@ void show_stack(struct task_struct *tsk, barrier(); } +#if (CONFIG_LTT) +asmlinkage void trace_real_syscall_entry(int scno,struct pt_regs * regs) +{ + int depth = 0; + unsigned long end_code; + unsigned long *fp; /* frame pointer */ + unsigned long lower_bound; + unsigned long lr; /* link register */ + unsigned long *prev_fp; + int seek_depth; + unsigned long start_code; + unsigned long *start_stack; + ltt_syscall_entry trace_syscall_event; + unsigned long upper_bound; + int use_bounds; + int use_depth; + + trace_syscall_event.syscall_id = (uint8_t)scno; + trace_syscall_event.address = instruction_pointer(regs); + + if (! (user_mode(regs) )) + goto trace_syscall_end; + + if (ltt_get_trace_config(&use_depth, &use_bounds, &seek_depth, + (void*)&lower_bound, (void*)&upper_bound) < 0) + goto trace_syscall_end; + + if ((use_depth == 1) || (use_bounds == 1)) { + fp = (unsigned long *)regs->ARM_fp; + end_code = current->mm->end_code; + start_code = current->mm->start_code; + start_stack = (unsigned long *)current->mm->start_stack; + + while (!__get_user(lr, (unsigned long *)(fp - 1))) { + if ((lr > start_code) && (lr < end_code)) { + if (((use_depth == 1) && (depth >= seek_depth)) || + ((use_bounds == 1) && (lr > lower_bound) && (lr < upper_bound))) { + trace_syscall_event.address = lr; + goto trace_syscall_end; + } else { + depth++; + } + } + + if ((__get_user((unsigned long)prev_fp, (fp - 3))) || + (prev_fp > start_stack) || + (prev_fp <= fp)) { + goto trace_syscall_end; + } + fp = prev_fp; + } + } + +trace_syscall_end: + ltt_log_event(LTT_EV_SYSCALL_ENTRY, &trace_syscall_event); +} + +asmlinkage void trace_real_syscall_exit(void) +{ + ltt_log_event(LTT_EV_SYSCALL_EXIT, NULL); +} +#endif /* (CONFIG_LTT) */ + spinlock_t die_lock = SPIN_LOCK_UNLOCKED; /* @@ -307,8 +371,12 @@ asmlinkage void do_undefinstr(struct pt_ info.si_code = ILL_ILLOPC; info.si_addr = pc; + ltt_ev_trap_entry(current->thread.trap_no, (uint32_t)pc); + force_sig_info(SIGILL, &info, current); + ltt_ev_trap_exit(); + die_if_kernel("Oops - undefined instruction", regs, 0); } @@ -512,7 +580,12 @@ baddataabort(int code, unsigned long ins info.si_code = ILL_ILLOPC; info.si_addr = (void __user *)addr; + ltt_ev_trap_entry(18, addr); /* machine check */ + force_sig_info(SIGILL, &info, current); + + ltt_ev_trap_exit(); + die_if_kernel("unknown data abort code", regs, instr); } diff -urpN linux-2.6.10-relayfs/arch/i386/kernel/entry.S linux-2.6.10-relayfs-ltt/arch/i386/kernel/entry.S --- linux-2.6.10-relayfs/arch/i386/kernel/entry.S 2004-12-24 16:34:27.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/i386/kernel/entry.S 2005-01-13 22:21:44.000000000 -0500 @@ -251,9 +251,27 @@ ENTRY(system_call) cmpl $(nr_syscalls), %eax jae syscall_badsys syscall_call: +#if (CONFIG_LTT) + movl syscall_entry_trace_active, %eax + cmpl $1, %eax # are we tracing system call entries + jne no_syscall_entry_trace + movl %esp, %eax # copy the stack pointer + pushl %eax # pass the stack pointer copy + call trace_real_syscall_entry + addl $4,%esp # return stack to state before pass +no_syscall_entry_trace: + movl ORIG_EAX(%esp),%eax # restore eax to it's original content +#endif call *sys_call_table(,%eax,4) movl %eax,EAX(%esp) # store the return value syscall_exit: +#if (CONFIG_LTT) + movl syscall_exit_trace_active, %eax + cmpl $1, %eax # are we tracing system call exits + jne no_syscall_exit_trace + call trace_real_syscall_exit +no_syscall_exit_trace: +#endif cli # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret diff -urpN linux-2.6.10-relayfs/arch/i386/kernel/process.c linux-2.6.10-relayfs-ltt/arch/i386/kernel/process.c --- linux-2.6.10-relayfs/arch/i386/kernel/process.c 2004-12-24 16:33:47.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/i386/kernel/process.c 2005-01-13 22:21:44.000000000 -0500 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -281,6 +282,7 @@ __asm__(".section .text\n" int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { struct pt_regs regs; + long pid; memset(®s, 0, sizeof(regs)); @@ -295,7 +297,12 @@ int kernel_thread(int (*fn)(void *), voi regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); +#if (CONFIG_LTT) + if(pid >= 0) + ltt_ev_process(LTT_EV_PROCESS_KTHREAD, pid, (int) fn); +#endif + return pid; } /* diff -urpN linux-2.6.10-relayfs/arch/i386/kernel/sys_i386.c linux-2.6.10-relayfs-ltt/arch/i386/kernel/sys_i386.c --- linux-2.6.10-relayfs/arch/i386/kernel/sys_i386.c 2004-12-24 16:35:39.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/i386/kernel/sys_i386.c 2005-01-13 22:21:44.000000000 -0500 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -136,6 +137,8 @@ asmlinkage int sys_ipc (uint call, int f version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; + ltt_ev_ipc(LTT_EV_IPC_CALL, call, first); + switch (call) { case SEMOP: return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL); diff -urpN linux-2.6.10-relayfs/arch/i386/kernel/traps.c linux-2.6.10-relayfs-ltt/arch/i386/kernel/traps.c --- linux-2.6.10-relayfs/arch/i386/kernel/traps.c 2004-12-24 16:34:01.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/i386/kernel/traps.c 2005-01-13 23:51:11.000000000 -0500 @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef CONFIG_EISA #include @@ -293,6 +294,73 @@ bug: printk("Kernel BUG\n"); } +/* Trace related code */ +#if (CONFIG_LTT) +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; + ltt_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 (ltt_get_trace_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 */ + ltt_log_event(LTT_EV_SYSCALL_ENTRY, &trace_syscall_event); +} + +asmlinkage void trace_real_syscall_exit(void) +{ + ltt_log_event(LTT_EV_SYSCALL_EXIT, NULL); +} +#endif /* (CONFIG_LTT) */ + void die(const char * str, struct pt_regs * regs, long err) { static struct { @@ -361,6 +429,8 @@ static inline void die_if_kernel(const c static void do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs * regs, long error_code, siginfo_t *info) { + ltt_ev_trap_entry(trapnr, regs->eip); + if (regs->eflags & VM_MASK) { if (vm86) goto vm86_trap; @@ -378,20 +448,24 @@ static void do_trap(int trapnr, int sign force_sig_info(signr, info, tsk); else force_sig(signr, tsk); + ltt_ev_trap_exit(); return; } kernel_trap: { if (!fixup_exception(regs)) die(str, regs, error_code); + ltt_ev_trap_exit(); return; } vm86_trap: { int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr); if (ret) goto trap_signal; + ltt_ev_trap_exit(); return; } + ltt_ev_trap_exit(); } #define DO_ERROR(trapnr, signr, str, name) \ @@ -493,12 +567,16 @@ fastcall void do_general_protection(stru current->thread.error_code = error_code; current->thread.trap_no = 13; + ltt_ev_trap_entry(13, regs->eip); force_sig(SIGSEGV, current); + ltt_ev_trap_exit(); return; gp_in_vm86: local_irq_enable(); + ltt_ev_trap_entry(13, regs->eip); handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); + ltt_ev_trap_exit(); return; gp_in_kernel: @@ -579,6 +657,12 @@ static void default_do_nmi(struct pt_reg /* Only the BSP gets external NMIs from the system. */ if (!smp_processor_id()) reason = get_nmi_reason(); + +#ifndef CONFIG_X86_LOCAL_APIC +/* On machines with APIC enabled, NMIs are used to implement a watchdog +and will hang the machine if traced. */ + ltt_ev_trap_entry(2, regs->eip); +#endif if (!(reason & 0xc0)) { if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) @@ -595,6 +679,9 @@ static void default_do_nmi(struct pt_reg } #endif unknown_nmi_error(reason, regs); +#ifndef CONFIG_X86_LOCAL_APIC + ltt_ev_trap_exit(); +#endif return; } if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP) @@ -608,6 +695,10 @@ static void default_do_nmi(struct pt_reg * as it's edge-triggered. */ reassert_nmi(); + +#ifndef CONFIG_X86_LOCAL_APIC + ltt_ev_trap_exit(); +#endif } static int dummy_nmi_callback(struct pt_regs * regs, int cpu) @@ -734,7 +825,9 @@ fastcall void do_debug(struct pt_regs * */ info.si_addr = ((regs->xcs & 3) == 0) ? (void __user *)tsk->thread.eip : (void __user *)regs->eip; + ltt_ev_trap_entry(1, regs->eip); force_sig_info(SIGTRAP, &info, tsk); + ltt_ev_trap_exit(); /* Disable additional traps. They'll be re-enabled when * the signal is delivered. @@ -746,7 +839,9 @@ clear_dr7: return; debug_vm86: + ltt_ev_trap_entry(1, regs->eip); handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); + ltt_ev_trap_exit(); return; clear_TF_reenable: @@ -898,10 +993,12 @@ fastcall void do_simd_coprocessor_error( fastcall void do_spurious_interrupt_bug(struct pt_regs * regs, long error_code) { + ltt_ev_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 + ltt_ev_trap_exit(); } /* @@ -932,8 +1029,10 @@ asmlinkage void math_emulate(long arg) { printk("math-emulation not enabled and no coprocessor found.\n"); printk("killing %s.\n",current->comm); + ltt_ev_trap_entry(7, 0); force_sig(SIGFPE,current); schedule(); + ltt_ev_trap_exit(); } #endif /* CONFIG_MATH_EMULATION */ @@ -965,7 +1064,6 @@ do { \ "3" ((char *) (addr)),"2" ((seg) << 16)); \ } while (0) - /* * This needs to use 'idt_table' rather than 'idt', and * thus use the _nonmapped_ version of the IDT, as the diff -urpN linux-2.6.10-relayfs/arch/i386/mm/fault.c linux-2.6.10-relayfs-ltt/arch/i386/mm/fault.c --- linux-2.6.10-relayfs/arch/i386/mm/fault.c 2004-12-24 16:33:48.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/i386/mm/fault.c 2005-01-13 22:21:44.000000000 -0500 @@ -21,6 +21,7 @@ #include /* For unblank_screen() */ #include #include +#include #include #include @@ -269,6 +270,8 @@ fastcall void do_page_fault(struct pt_re if (in_atomic() || !mm) goto bad_area_nosemaphore; + ltt_ev_trap_entry(14, regs->eip); + /* When running in the kernel we expect faults to occur only to * addresses in user space. All other faults represent errors in the * kernel and should generate an OOPS. Unfortunatly, in the case of an @@ -366,6 +369,7 @@ good_area: tsk->thread.screen_bitmap |= 1 << bit; } up_read(&mm->mmap_sem); + ltt_ev_trap_exit(); return; /* @@ -408,6 +412,7 @@ bad_area_nosemaphore: if (nr == 6) { do_invalid_op(regs, 0); + ltt_ev_trap_exit(); return; } } @@ -415,16 +420,20 @@ bad_area_nosemaphore: no_context: /* Are we prepared to handle this kernel fault? */ - if (fixup_exception(regs)) + if (fixup_exception(regs)) { + ltt_ev_trap_exit(); return; + } /* * Valid to do another page fault here, because if this fault * had been triggered by is_prefetch fixup_exception would have * handled it. */ - if (is_prefetch(regs, address, error_code)) + if (is_prefetch(regs, address, error_code)) { + ltt_ev_trap_exit(); return; + } /* * Oops. The kernel tried to access some bad page. We'll have to @@ -493,8 +502,10 @@ do_sigbus: goto no_context; /* User space => ok to do another page fault */ - if (is_prefetch(regs, address, error_code)) + if (is_prefetch(regs, address, error_code)) { + ltt_ev_trap_exit(); return; + } tsk->thread.cr2 = address; tsk->thread.error_code = error_code; @@ -504,6 +515,7 @@ do_sigbus: info.si_code = BUS_ADRERR; info.si_addr = (void __user *)address; force_sig_info(SIGBUS, &info, tsk); + ltt_ev_trap_exit(); return; vmalloc_fault: @@ -542,6 +554,9 @@ vmalloc_fault: pte_k = pte_offset_kernel(pmd_k, address); if (!pte_present(*pte_k)) goto no_context; + ltt_ev_trap_entry(14, regs->eip); + ltt_ev_trap_exit(); return; } + ltt_ev_trap_exit(); } diff -urpN linux-2.6.10-relayfs/arch/mips/kernel/irq.c linux-2.6.10-relayfs-ltt/arch/mips/kernel/irq.c --- linux-2.6.10-relayfs/arch/mips/kernel/irq.c 2004-12-24 16:34:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/mips/kernel/irq.c 2005-01-13 23:53:28.000000000 -0500 @@ -49,8 +49,12 @@ asmlinkage unsigned int do_IRQ(unsigned { irq_enter(); + ltt_ev_irq_entry(irq, !(user_mode(regs))); + __do_IRQ(irq, regs); + ltt_ev_irq_exit(); + irq_exit(); return 1; diff -urpN linux-2.6.10-relayfs/arch/mips/kernel/traps.c linux-2.6.10-relayfs-ltt/arch/mips/kernel/traps.c --- linux-2.6.10-relayfs/arch/mips/kernel/traps.c 2004-12-24 16:34:32.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/mips/kernel/traps.c 2005-01-13 23:53:59.000000000 -0500 @@ -501,6 +501,7 @@ asmlinkage void do_ov(struct pt_regs *re */ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) { + ltt_ev_trap_entry(CAUSE_EXCCODE(regs), CAUSE_EPC(regs)); if (fcr31 & FPU_CSR_UNI_X) { int sig; @@ -640,6 +641,8 @@ asmlinkage void do_cpu(struct pt_regs *r die_if_kernel("do_cpu invoked from kernel context!", regs); + ltt_ev_trap_entry(CAUSE_EXCCODE(regs), CAUSE_EPC(regs)); + cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; switch (cpid) { @@ -1060,3 +1063,72 @@ void __init trap_init(void) flush_icache_range(CAC_BASE, CAC_BASE + 0x400); } + +#if (CONFIG_LTT) +asmlinkage void trace_real_syscall_entry(struct pt_regs * regs) +{ + unsigned long addr; + int depth = 0; + unsigned long end_code; + unsigned long lower_bound; + int seek_depth; + unsigned long *stack; + unsigned long start_code; + unsigned long *start_stack; + ltt_syscall_entry trace_syscall_event; + unsigned long upper_bound; + int use_bounds; + int use_depth; + + /* syscall_id will be negative for SVR4, IRIX5, BSD43, and POSIX + * syscalls -- these are not supported at this point by LTT + */ + trace_syscall_event.syscall_id = (uint8_t) (regs->regs[2] - __NR_Linux); + + trace_syscall_event.address = regs->cp0_epc; + + if (!user_mode(regs)) + goto trace_syscall_end; + + if (trace_get_config(&use_depth, &use_bounds, &seek_depth, + (void*)&lower_bound, (void*)&upper_bound) < 0) + goto trace_syscall_end; + + /* Heuristic that might work: + * (BUT DOESN'T WORK for any of the cases I tested...) zzz + * Search through stack until a value is found that is within the + * range start_code .. end_code. (This is looking for a return + * pointer to where a shared library was called from.) If a stack + * variable contains a valid code address then an incorrect + * result will be generated. + */ + if ((use_depth == 1) || (use_bounds == 1)) { + stack = (unsigned long*) regs->regs[29]; + end_code = current->mm->end_code; + start_code = current->mm->start_code; + start_stack = (unsigned long *)current->mm->start_stack; + + while ((stack <= start_stack) && (!__get_user(addr, stack))) { + if ((addr > start_code) && (addr < end_code)) { + if (((use_depth == 1) && (depth == seek_depth)) || + ((use_bounds == 1) && (addr > lower_bound) && (addr < upper_bound))) { + trace_syscall_event.address = addr; + goto trace_syscall_end; + } else { + depth++; + } + } + stack++; + } + } + +trace_syscall_end: + trace_event(LTT_EV_SYSCALL_ENTRY, &trace_syscall_event); +} + +asmlinkage void trace_real_syscall_exit(void) +{ + trace_event(LTT_EV_SYSCALL_EXIT, NULL); +} + +#endif /* (CONFIG_LTT) */ diff -urpN linux-2.6.10-relayfs/arch/mips/kernel/unaligned.c linux-2.6.10-relayfs-ltt/arch/mips/kernel/unaligned.c --- linux-2.6.10-relayfs/arch/mips/kernel/unaligned.c 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/mips/kernel/unaligned.c 2005-01-13 23:56:54.000000000 -0500 @@ -78,6 +78,7 @@ #include #include #include +#include #include #include @@ -497,14 +498,18 @@ asmlinkage void do_ade(struct pt_regs *r mm_segment_t seg; unsigned long pc; + ltt_ev_trap_entry(CAUSE_EXCCODE(regs), CAUSE_EPC(regs)); + /* * Address errors may be deliberately induced by the FPU emulator to * retake control of the CPU after executing the instruction in the * delay slot of an emulated branch. */ /* Terminate if exception was recognized as a delay slot return */ - if (do_dsemulret(regs)) + if (do_dsemulret(regs)) { + ltt_ev_trap_exit(); return; + } /* Otherwise handle as normal */ @@ -538,6 +543,8 @@ asmlinkage void do_ade(struct pt_regs *r } set_fs(seg); + ltt_ev_trap_exit(); + return; sigbus: @@ -547,4 +554,6 @@ sigbus: /* * XXX On return from the signal handler we should advance the epc */ + + ltt_ev_trap_exit(); } diff -urpN linux-2.6.10-relayfs/arch/mips/mm/fault.c linux-2.6.10-relayfs-ltt/arch/mips/mm/fault.c --- linux-2.6.10-relayfs/arch/mips/mm/fault.c 2004-12-24 16:34:29.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/mips/mm/fault.c 2005-01-13 22:21:44.000000000 -0500 @@ -60,6 +60,8 @@ asmlinkage void do_page_fault(struct pt_ if (unlikely(address >= VMALLOC_START)) goto vmalloc_fault; + ltt_ev_trap_entry(CAUSE_EXCCODE(regs), CAUSE_EPC(regs)); + /* * If we're in an interrupt or have no user * context, we must not take the fault.. @@ -114,6 +116,7 @@ survive: } up_read(&mm->mmap_sem); + ltt_ev_trap_exit(); return; /* @@ -142,6 +145,7 @@ bad_area_nosemaphore: /* info.si_code has been set above */ info.si_addr = (void *) address; force_sig_info(SIGSEGV, &info, tsk); + ltt_ev_trap_exit(); return; } @@ -199,6 +203,7 @@ do_sigbus: info.si_addr = (void *) address; force_sig_info(SIGBUS, &info, tsk); + ltt_ev_trap_exit(); return; vmalloc_fault: @@ -233,4 +238,5 @@ vmalloc_fault: goto no_context; return; } + ltt_ev_trap_exit(); } diff -urpN linux-2.6.10-relayfs/arch/ppc/kernel/entry.S linux-2.6.10-relayfs-ltt/arch/ppc/kernel/entry.S --- linux-2.6.10-relayfs/arch/ppc/kernel/entry.S 2004-12-24 16:35:27.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/ppc/kernel/entry.S 2005-01-13 22:21:44.000000000 -0500 @@ -156,6 +156,34 @@ transfer_to_handler_cont: SYNC RFI /* jump to handler, enable MMU */ +/* LTT stuff */ +#if (CONFIG_LTT) +#define TRACE_REAL_ASM_SYSCALL_ENTRY \ + SAVE_NVGPRS(r1); \ + 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); \ + REST_NVGPRS(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 + /* * On kernel stack overflow, load up an initial stack pointer * and call StackOverflow(regs), which should not return. @@ -213,6 +241,9 @@ syscall_dotrace_cont: bge- 66f lwzx r10,r10,r0 /* Fetch system call handler [ptr] */ mtlr r10 +#if (CONFIG_LTT) + TRACE_REAL_ASM_SYSCALL_ENTRY ; +#endif addi r9,r1,STACK_FRAME_OVERHEAD blrl /* Call handler */ .globl ret_from_syscall @@ -220,6 +251,10 @@ ret_from_syscall: #ifdef SHOW_SYSCALLS bl do_show_syscall_exit #endif +#if (CONFIG_LTT) + stw r3,RESULT(r1) /* Save result */ + TRACE_REAL_ASM_SYSCALL_EXIT ; +#endif mr r6,r3 li r11,-_LAST_ERRNO cmplw 0,r3,r11 diff -urpN linux-2.6.10-relayfs/arch/ppc/kernel/misc.S linux-2.6.10-relayfs-ltt/arch/ppc/kernel/misc.S --- linux-2.6.10-relayfs/arch/ppc/kernel/misc.S 2004-12-24 16:35:28.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/ppc/kernel/misc.S 2005-01-13 22:21:44.000000000 -0500 @@ -1130,7 +1130,11 @@ _GLOBAL(cvt_df) * Create a kernel thread * kernel_thread(fn, arg, flags) */ +#if (CONFIG_LTT) +_GLOBAL(original_kernel_thread) +#else _GLOBAL(kernel_thread) +#endif /* (CONFIG_LTT) */ stwu r1,-16(r1) stw r30,8(r1) stw r31,12(r1) diff -urpN linux-2.6.10-relayfs/arch/ppc/kernel/process.c linux-2.6.10-relayfs-ltt/arch/ppc/kernel/process.c --- linux-2.6.10-relayfs/arch/ppc/kernel/process.c 2004-12-24 16:34:45.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/ppc/kernel/process.c 2005-01-13 22:21:44.000000000 -0500 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -364,6 +365,19 @@ void show_regs(struct pt_regs * regs) show_stack(current, (unsigned long *) regs->gpr[1]); } +#if (CONFIG_LTT) +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) + ltt_ev_process(LTT_EV_PROCESS_KTHREAD, retval, (int) fn); + return retval; +} +#endif /* (CONFIG_LTT) */ + void exit_thread(void) { if (last_task_used_math == current) diff -urpN linux-2.6.10-relayfs/arch/ppc/kernel/syscalls.c linux-2.6.10-relayfs-ltt/arch/ppc/kernel/syscalls.c --- linux-2.6.10-relayfs/arch/ppc/kernel/syscalls.c 2004-12-24 16:35:29.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/ppc/kernel/syscalls.c 2005-01-13 22:21:44.000000000 -0500 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,8 @@ sys_ipc (uint call, int first, int secon version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; + ltt_ev_ipc(LTT_EV_IPC_CALL, call, first); + ret = -ENOSYS; switch (call) { case SEMOP: diff -urpN linux-2.6.10-relayfs/arch/ppc/kernel/time.c linux-2.6.10-relayfs-ltt/arch/ppc/kernel/time.c --- linux-2.6.10-relayfs/arch/ppc/kernel/time.c 2004-12-24 16:35:23.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/ppc/kernel/time.c 2005-01-13 22:21:44.000000000 -0500 @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -136,6 +137,8 @@ void timer_interrupt(struct pt_regs * re if (atomic_read(&ppc_n_lost_interrupts) != 0) do_IRQ(regs); + ltt_ev_trap_entry(regs->trap, instruction_pointer(regs)); + irq_enter(); while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) { @@ -194,6 +197,8 @@ void timer_interrupt(struct pt_regs * re ppc_md.heartbeat(); irq_exit(); + + ltt_ev_trap_exit(); } /* diff -urpN linux-2.6.10-relayfs/arch/ppc/kernel/traps.c linux-2.6.10-relayfs-ltt/arch/ppc/kernel/traps.c --- linux-2.6.10-relayfs/arch/ppc/kernel/traps.c 2004-12-24 16:34:26.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/ppc/kernel/traps.c 2005-01-13 23:58:26.000000000 -0500 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -601,6 +602,81 @@ void StackOverflow(struct pt_regs *regs) panic("kernel stack overflow"); } +/* Trace related code */ +#if (CONFIG_LTT) +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; + ltt_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 (ltt_get_trace_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 */ + ltt_log_event(LTT_EV_SYSCALL_ENTRY, &trace_syscall_event); +} + +asmlinkage void trace_real_syscall_exit(void) +{ + ltt_log_event(LTT_EV_SYSCALL_EXIT, NULL); +} + +#endif /* (CONFIG_LTT) */ + void nonrecoverable_exception(struct pt_regs *regs) { printk(KERN_ERR "Non-recoverable exception at PC=%lx MSR=%lx\n", diff -urpN linux-2.6.10-relayfs/arch/ppc/mm/fault.c linux-2.6.10-relayfs-ltt/arch/ppc/mm/fault.c --- linux-2.6.10-relayfs/arch/ppc/mm/fault.c 2004-12-24 16:34:29.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/ppc/mm/fault.c 2005-01-14 00:02:02.000000000 -0500 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -116,22 +117,29 @@ int do_page_fault(struct pt_regs *regs, is_write = error_code & 0x02000000; #endif /* CONFIG_4xx || CONFIG_BOOKE */ + ltt_ev_trap_entry(regs->trap, instruction_pointer(regs)); + #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_fault_handler && TRAP(regs) == 0x300) { debugger_fault_handler(regs); + ltt_ev_trap_exit(); return 0; } #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) if (error_code & 0x00400000) { /* DABR match */ - if (debugger_dabr_match(regs)) + if (debugger_dabr_match(regs)) { + ltt_ev_trap_exit();; return 0; + } } #endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/ #endif /* CONFIG_XMON || CONFIG_KGDB */ - if (in_atomic() || mm == NULL) + if (in_atomic() || mm == NULL) { + ltt_ev_trap_exit(); return SIGSEGV; + } down_read(&mm->mmap_sem); vma = find_vma(mm, address); @@ -228,6 +236,7 @@ good_area: _tlbie(address); pte_unmap(ptep); up_read(&mm->mmap_sem); + ltt_ev_trap_exit(); return 0; } if (ptep != NULL) @@ -283,6 +292,7 @@ bad_area: info.si_code = code; info.si_addr = (void __user *) address; force_sig_info(SIGSEGV, &info, current); + ltt_ev_trap_exit(); return 0; } @@ -302,6 +312,7 @@ out_of_memory: printk("VM: killing process %s\n", current->comm); if (user_mode(regs)) do_exit(SIGKILL); + ltt_ev_trap_exit(); return SIGKILL; do_sigbus: @@ -311,6 +322,7 @@ do_sigbus: info.si_code = BUS_ADRERR; info.si_addr = (void __user *)address; force_sig_info (SIGBUS, &info, current); + ltt_ev_trap_exit(); if (!user_mode(regs)) return SIGBUS; return 0; diff -urpN linux-2.6.10-relayfs/arch/s390/kernel/entry.S linux-2.6.10-relayfs-ltt/arch/s390/kernel/entry.S --- linux-2.6.10-relayfs/arch/s390/kernel/entry.S 2004-12-24 16:34:02.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/s390/kernel/entry.S 2005-01-13 22:21:44.000000000 -0500 @@ -7,6 +7,7 @@ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Hartmut Penner (hp@de.ibm.com), * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), + * Portions added by T. Halloran: (C) Copyright 2002 IBM Poughkeepsie, IBM Corporation */ #include @@ -182,6 +183,13 @@ sysc_do_restart: # ATTENTION: check sys_execve_glue before # changing anything here !! +#if (CONFIG_LTT) /* tjh - ltt port */ + /* add call to trace_real_syscall_exit */ + la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter + l %r1,BASED(.Ltracesysext) + basr %r14,%r1 + lm %r0,%r6,SP_R0(%r15) /* restore call clobbered regs */ +#endif sysc_return: tm SP_PSW+1(%r15),0x01 # returning to user ? bno BASED(sysc_leave) diff -urpN linux-2.6.10-relayfs/arch/s390/kernel/sys_s390.c linux-2.6.10-relayfs-ltt/arch/s390/kernel/sys_s390.c --- linux-2.6.10-relayfs/arch/s390/kernel/sys_s390.c 2004-12-24 16:34:31.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/s390/kernel/sys_s390.c 2005-01-13 22:21:44.000000000 -0500 @@ -151,6 +151,8 @@ asmlinkage long sys_ipc(uint call, int f struct ipc_kludge tmp; int ret; + ltt_ev_ipc(LTT_EV_IPC_CALL, call, first); + switch (call) { case SEMOP: return sys_semtimedop (first, (struct sembuf __user *) ptr, second, diff -urpN linux-2.6.10-relayfs/arch/s390/kernel/traps.c linux-2.6.10-relayfs-ltt/arch/s390/kernel/traps.c --- linux-2.6.10-relayfs/arch/s390/kernel/traps.c 2004-12-24 16:34:30.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/s390/kernel/traps.c 2005-01-13 22:21:44.000000000 -0500 @@ -5,6 +5,7 @@ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), + * Portions added by T. Halloran: (C) Copyright 2002 IBM Poughkeepsie, IBM Corporation * * Derived from "arch/i386/kernel/traps.c" * Copyright (C) 1991, 1992 Linus Torvalds @@ -29,6 +30,7 @@ #include #include #include +#include #include #include @@ -311,6 +313,9 @@ report_user_fault(long interruption_code static void inline do_trap(long interruption_code, int signr, char *str, struct pt_regs *regs, siginfo_t *info) { + trapid_t ltt_interruption_code; + char * ic_ptr = (char *) <t_interruption_code; + /* * We got all needed information from the lowcore and can * now safely switch on interrupts. @@ -318,6 +323,10 @@ static void inline do_trap(long interrup if (regs->psw.mask & PSW_MASK_PSTATE) local_irq_enable(); + memset(<t_interruption_code,0,sizeof(ltt_interruption_code)); + memcpy(ic_ptr+4,&interruption_code,sizeof(interruption_code)); + ltt_ev_trap_entry(ltt_interruption_code, (regs->psw.addr & PSW_ADDR_INSN)); + if (regs->psw.mask & PSW_MASK_PSTATE) { struct task_struct *tsk = current; @@ -332,6 +341,7 @@ static void inline do_trap(long interrup else die(str, regs, interruption_code); } + ltt_ev_trap_exit(); } static inline void *get_check_address(struct pt_regs *regs) @@ -428,6 +438,8 @@ asmlinkage void illegal_op(struct pt_reg siginfo_t info; __u8 opcode[6]; __u16 *location; + trapid_t ltt_interruption_code; + char * ic_ptr = (char *) <t_interruption_code; int signal = 0; location = (__u16 *) get_check_address(regs); @@ -490,6 +502,7 @@ asmlinkage void illegal_op(struct pt_reg do_trap(interruption_code, signal, "illegal operation", regs, &info); } + ltt_ev_trap_exit(); } @@ -499,6 +512,8 @@ specification_exception(struct pt_regs * { __u8 opcode[6]; __u16 *location = NULL; + trapid_t ltt_interruption_code; + char * ic_ptr = (char *) <t_interruption_code; int signal = 0; location = (__u16 *) get_check_address(regs); @@ -554,6 +569,7 @@ specification_exception(struct pt_regs * do_trap(interruption_code, signal, "specification exception", regs, &info); } + ltt_ev_trap_exit(); } #else DO_ERROR_INFO(SIGILL, "specification exception", specification_exception, @@ -563,6 +579,8 @@ DO_ERROR_INFO(SIGILL, "specification exc asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) { __u16 *location; + trapid_t ltt_interruption_code; + char * ic_ptr = (char *) <t_interruption_code; int signal = 0; location = (__u16 *) get_check_address(regs); @@ -574,6 +592,10 @@ asmlinkage void data_exception(struct pt if (regs->psw.mask & PSW_MASK_PSTATE) local_irq_enable(); + memset(<t_interruption_code,0,sizeof(ltt_interruption_code)); + memcpy(ic_ptr+4,&interruption_code,sizeof(interruption_code)); + ltt_ev_trap_entry(ltt_interruption_code, (regs->psw.addr & PSW_ADDR_INSN)); + if (MACHINE_HAS_IEEE) __asm__ volatile ("stfpc %0\n\t" : "=m" (current->thread.fp_regs.fpc)); @@ -649,6 +671,7 @@ asmlinkage void data_exception(struct pt do_trap(interruption_code, signal, "data exception", regs, &info); } + ltt_ev_trap_exit(); } asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code) diff -urpN linux-2.6.10-relayfs/arch/s390/mm/fault.c linux-2.6.10-relayfs-ltt/arch/s390/mm/fault.c --- linux-2.6.10-relayfs/arch/s390/mm/fault.c 2004-12-24 16:36:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/s390/mm/fault.c 2005-01-13 22:21:44.000000000 -0500 @@ -5,6 +5,7 @@ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Hartmut Penner (hp@de.ibm.com) * Ulrich Weigand (uweigand@de.ibm.com) + * Portions added by T. Halloran: (C) Copyright 2002 IBM Poughkeepsie, IBM Corporation * * Derived from "arch/i386/mm/fault.c" * Copyright (C) 1995 Linus Torvalds @@ -169,6 +170,8 @@ do_exception(struct pt_regs *regs, unsig int user_address; const struct exception_table_entry *fixup; int si_code = SEGV_MAPERR; + trapid_t ltt_interruption_code; + char * ic_ptr = (char *) <t_interruption_code; tsk = current; mm = tsk->mm; @@ -216,6 +219,9 @@ do_exception(struct pt_regs *regs, unsig */ local_irq_enable(); + memset(<t_interruption_code,0,sizeof(ltt_interruption_code)); + memcpy(ic_ptr+4,&error_code,sizeof(error_code)); + ltt_ev_trap_entry(ltt_interruption_code,(regs->psw.addr & PSW_ADDR_INSN)); down_read(&mm->mmap_sem); vma = find_vma(mm, address); @@ -283,6 +289,7 @@ bad_area: tsk->thread.prot_addr = address; tsk->thread.trap_no = error_code; do_sigsegv(regs, error_code, si_code, address); + ltt_ev_trap_exit(); return; } @@ -338,6 +345,8 @@ do_sigbus: /* Kernel mode? Handle exceptions or die */ if (!(regs->psw.mask & PSW_MASK_PSTATE)) goto no_context; + + ltt_ev_trap_exit(); } void do_protection_exception(struct pt_regs *regs, unsigned long error_code) diff -urpN linux-2.6.10-relayfs/arch/sh/kernel/irq.c linux-2.6.10-relayfs-ltt/arch/sh/kernel/irq.c --- linux-2.6.10-relayfs/arch/sh/kernel/irq.c 2004-12-24 16:34:31.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/sh/kernel/irq.c 2005-01-13 22:21:44.000000000 -0500 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff -urpN linux-2.6.10-relayfs/arch/sh/kernel/process.c linux-2.6.10-relayfs-ltt/arch/sh/kernel/process.c --- linux-2.6.10-relayfs/arch/sh/kernel/process.c 2004-12-24 16:35:23.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/sh/kernel/process.c 2005-01-13 22:21:44.000000000 -0500 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff -urpN linux-2.6.10-relayfs/arch/sh/kernel/sys_sh.c linux-2.6.10-relayfs-ltt/arch/sh/kernel/sys_sh.c --- linux-2.6.10-relayfs/arch/sh/kernel/sys_sh.c 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/sh/kernel/sys_sh.c 2005-01-13 22:21:44.000000000 -0500 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -166,6 +167,8 @@ asmlinkage int sys_ipc(uint call, int fi version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; + ltt_ev_ipc(LTT_EV_IPC_CALL, call, first); + if (call <= SEMCTL) switch (call) { case SEMOP: diff -urpN linux-2.6.10-relayfs/arch/sh/kernel/traps.c linux-2.6.10-relayfs-ltt/arch/sh/kernel/traps.c --- linux-2.6.10-relayfs/arch/sh/kernel/traps.c 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/sh/kernel/traps.c 2005-01-14 00:04:25.000000000 -0500 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -500,6 +501,8 @@ asmlinkage void do_address_error(struct asm volatile("stc r2_bank,%0": "=r" (error_code)); + ltt_ev_trap_entry(error_code >> 5, regs->pc); + oldfs = get_fs(); if (user_mode(regs)) { @@ -523,8 +526,10 @@ asmlinkage void do_address_error(struct tmp = handle_unaligned_access(instruction, regs); set_fs(oldfs); - if (tmp==0) - return; /* sorted */ + if (tmp==0) { + ltt_ev_trap_exit(); + return; /* sorted */ + } uspace_segv: printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm); @@ -545,6 +550,7 @@ asmlinkage void do_address_error(struct handle_unaligned_access(instruction, regs); set_fs(oldfs); } + ltt_ev_trap_exit(); } #ifdef CONFIG_SH_DSP @@ -704,6 +710,74 @@ void show_task(unsigned long *sp) { show_stack(NULL, sp); } +/* Trace related code */ +#if (CONFIG_LTT) +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; + ltt_syscall_entry trace_syscall_event; + + /* Set the syscall ID */ + trace_syscall_event.syscall_id = (uint8_t) regs->regs[REG_REG0 + 3]; + + /* Set the address in any case */ + trace_syscall_event.address = regs->pc; + + /* 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 (ltt_get_trace_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->regs[REG_REG15]; + + /* 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 */ + /* TODO: does this work with shared libraries?? - Greg Banks */ + 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 */ + ltt_log_event(LTT_EV_SYSCALL_ENTRY, &trace_syscall_event); +} + +asmlinkage void trace_real_syscall_exit(void) +{ + ltt_log_event(LTT_EV_SYSCALL_EXIT, NULL); +} + +#endif /* (CONFIG_LTT) */ void dump_stack(void) { diff -urpN linux-2.6.10-relayfs/arch/sh/mm/fault.c linux-2.6.10-relayfs-ltt/arch/sh/mm/fault.c --- linux-2.6.10-relayfs/arch/sh/mm/fault.c 2004-12-24 16:34:29.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/arch/sh/mm/fault.c 2005-01-13 22:21:44.000000000 -0500 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,14 @@ asmlinkage void do_page_fault(struct pt_ tsk = current; mm = tsk->mm; +#if (CONFIG_LTT) + { + unsigned long trapnr; + asm volatile("stc r2_bank,%0": "=r" (trapnr)); + ltt_ev_trap_entry(trapnr >> 5, regs->pc); /* trap 4,5 or 6 */ + } +#endif + /* * If we're in an interrupt or have no user * context, we must not take the fault.. @@ -106,6 +115,7 @@ survive: } up_read(&mm->mmap_sem); + ltt_ev_trap_exit(); return; /* @@ -119,6 +129,7 @@ bad_area: tsk->thread.address = address; tsk->thread.error_code = writeaccess; force_sig(SIGSEGV, tsk); + ltt_ev_trap_exit(); return; } @@ -185,6 +196,8 @@ do_sigbus: /* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) goto no_context; + + ltt_ev_trap_exit(); } /* diff -urpN linux-2.6.10-relayfs/fs/buffer.c linux-2.6.10-relayfs-ltt/fs/buffer.c --- linux-2.6.10-relayfs/fs/buffer.c 2004-12-24 16:34:58.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/fs/buffer.c 2005-01-13 22:21:51.000000000 -0500 @@ -39,6 +39,7 @@ #include #include #include +#include static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); static void invalidate_bh_lrus(void); @@ -87,7 +88,9 @@ void fastcall unlock_buffer(struct buffe */ void __wait_on_buffer(struct buffer_head * bh) { + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_BUF_WAIT_START, 0, 0, NULL); wait_on_bit(&bh->b_state, BH_Lock, sync_buffer, TASK_UNINTERRUPTIBLE); + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_BUF_WAIT_END, 0, 0, NULL); } static void diff -urpN linux-2.6.10-relayfs/fs/exec.c linux-2.6.10-relayfs-ltt/fs/exec.c --- linux-2.6.10-relayfs/fs/exec.c 2004-12-24 16:34:31.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/fs/exec.c 2005-01-13 23:37:48.000000000 -0500 @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -1105,6 +1106,9 @@ int do_execve(char * filename, if (IS_ERR(file)) goto out_kfree; + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_EXEC, 0, + file->f_dentry->d_name.len, file->f_dentry->d_name.name); + sched_exec(); bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); diff -urpN linux-2.6.10-relayfs/fs/ioctl.c linux-2.6.10-relayfs-ltt/fs/ioctl.c --- linux-2.6.10-relayfs/fs/ioctl.c 2004-12-24 16:34:26.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/fs/ioctl.c 2005-01-13 22:35:41.000000000 -0500 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,8 @@ asmlinkage long sys_ioctl(unsigned int f goto out; } + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_IOCTL, fd, cmd, NULL); + lock_kernel(); switch (cmd) { case FIOCLEX: diff -urpN linux-2.6.10-relayfs/fs/open.c linux-2.6.10-relayfs-ltt/fs/open.c --- linux-2.6.10-relayfs/fs/open.c 2004-12-24 16:33:50.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/fs/open.c 2005-01-13 23:38:31.000000000 -0500 @@ -19,6 +19,8 @@ #include #include #include +#include + #include #include #include @@ -956,6 +958,8 @@ asmlinkage long sys_open(const char __us error = PTR_ERR(f); if (IS_ERR(f)) goto out_error; + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_OPEN, fd, + f->f_dentry->d_name.len, f->f_dentry->d_name.name); fd_install(fd, f); } out: @@ -1031,6 +1035,7 @@ asmlinkage long sys_close(unsigned int f filp = files->fd[fd]; if (!filp) goto out_unlock; + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_CLOSE, fd, 0, NULL); files->fd[fd] = NULL; FD_CLR(fd, files->close_on_exec); __put_unused_fd(files, fd); diff -urpN linux-2.6.10-relayfs/fs/read_write.c linux-2.6.10-relayfs-ltt/fs/read_write.c --- linux-2.6.10-relayfs/fs/read_write.c 2004-12-24 16:35:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/fs/read_write.c 2005-01-13 23:39:41.000000000 -0500 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -142,6 +143,9 @@ asmlinkage off_t sys_lseek(unsigned int if (res != (loff_t)retval) retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ } + + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_SEEK, fd, offset, NULL); + fput_light(file, fput_needed); bad: return retval; @@ -169,6 +173,8 @@ asmlinkage long sys_llseek(unsigned int offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low, origin); + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_SEEK, fd, offset, NULL); + retval = (int)offset; if (offset >= 0) { retval = -EFAULT; @@ -289,6 +295,7 @@ asmlinkage ssize_t sys_read(unsigned int file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_READ, fd, count, NULL); ret = vfs_read(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); @@ -307,6 +314,7 @@ asmlinkage ssize_t sys_write(unsigned in file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_WRITE, fd, count, NULL); ret = vfs_write(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); @@ -328,8 +336,11 @@ asmlinkage ssize_t sys_pread64(unsigned file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; - if (file->f_mode & FMODE_PREAD) + if (file->f_mode & FMODE_PREAD) { + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_READ, fd, count, NULL); ret = vfs_read(file, buf, count, &pos); + } + fput_light(file, fput_needed); } @@ -349,8 +360,10 @@ asmlinkage ssize_t sys_pwrite64(unsigned file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; - if (file->f_mode & FMODE_PWRITE) + if (file->f_mode & FMODE_PWRITE) { + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_WRITE, fd, count, NULL); ret = vfs_write(file, buf, count, &pos); + } fput_light(file, fput_needed); } @@ -535,6 +548,7 @@ sys_readv(unsigned long fd, const struct file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_READ, fd, vlen, NULL); ret = vfs_readv(file, vec, vlen, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); @@ -553,6 +567,7 @@ sys_writev(unsigned long fd, const struc file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_WRITE, fd, vlen, NULL); ret = vfs_writev(file, vec, vlen, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); diff -urpN linux-2.6.10-relayfs/fs/relayfs/relay.c linux-2.6.10-relayfs-ltt/fs/relayfs/relay.c --- linux-2.6.10-relayfs/fs/relayfs/relay.c 2005-01-13 22:16:35.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/fs/relayfs/relay.c 2005-01-14 00:12:06.000000000 -0500 @@ -406,8 +406,7 @@ relay_mmap_region(struct vm_area_struct while (size > 0) { page = kvirt_to_pa(pos); - if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, - PAGE_SIZE, PAGE_SHARED)) + if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; start += PAGE_SIZE; pos += PAGE_SIZE; diff -urpN linux-2.6.10-relayfs/fs/select.c linux-2.6.10-relayfs-ltt/fs/select.c --- linux-2.6.10-relayfs/fs/select.c 2004-12-24 16:33:49.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/fs/select.c 2005-01-13 23:39:55.000000000 -0500 @@ -22,6 +22,7 @@ #include /* for STICKY_TIMEOUTS */ #include #include +#include #include @@ -223,6 +224,8 @@ int do_select(int n, fd_set_bits *fds, l file = fget(i); if (file) { f_op = file->f_op; + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_SELECT, i /* The fd*/, + __timeout, NULL); mask = DEFAULT_POLLMASK; if (f_op && f_op->poll) mask = (*f_op->poll)(file, retval ? NULL : wait); @@ -408,6 +411,7 @@ static void do_pollfd(unsigned int num, struct file * file = fget(fd); mask = POLLNVAL; if (file != NULL) { + ltt_ev_file_system(LTT_EV_FILE_SYSTEM_POLL, fd, 0, NULL); mask = DEFAULT_POLLMASK; if (file->f_op && file->f_op->poll) mask = file->f_op->poll(file, *pwait); diff -urpN linux-2.6.10-relayfs/include/asm-arm/ltt.h linux-2.6.10-relayfs-ltt/include/asm-arm/ltt.h --- linux-2.6.10-relayfs/include/asm-arm/ltt.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/include/asm-arm/ltt.h 2005-01-13 22:21:44.000000000 -0500 @@ -0,0 +1,15 @@ +/* + * linux/include/asm-arm/ltt.h + * + * Copyright (C) 2002, Karim Yaghmour + * + * ARM definitions for tracing system + */ + +#include + +/* Current arch type */ +#define LTT_ARCH_TYPE LTT_ARCH_TYPE_ARM + +/* Current variant type */ +#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE diff -urpN linux-2.6.10-relayfs/include/asm-i386/ltt.h linux-2.6.10-relayfs-ltt/include/asm-i386/ltt.h --- linux-2.6.10-relayfs/include/asm-i386/ltt.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/include/asm-i386/ltt.h 2005-01-13 22:21:44.000000000 -0500 @@ -0,0 +1,15 @@ +/* + * linux/include/asm-i386/ltt.h + * + * Copyright (C) 2002, Karim Yaghmour + * + * i386 definitions for tracing system + */ + +#include + +/* Current arch type */ +#define LTT_ARCH_TYPE LTT_ARCH_TYPE_I386 + +/* Current variant type */ +#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE diff -urpN linux-2.6.10-relayfs/include/asm-mips/ltt.h linux-2.6.10-relayfs-ltt/include/asm-mips/ltt.h --- linux-2.6.10-relayfs/include/asm-mips/ltt.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/include/asm-mips/ltt.h 2005-01-13 22:21:44.000000000 -0500 @@ -0,0 +1,15 @@ +/* + * linux/include/asm-mips/ltt.h + * + * Copyright (C) 2002, Karim Yaghmour + * + * MIPS definitions for tracing system + */ + +#include + +/* Current arch type */ +#define LTT_ARCH_TYPE LTT_ARCH_TYPE_MIPS + +/* Current variant type */ +#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE diff -urpN linux-2.6.10-relayfs/include/asm-ppc/ltt.h linux-2.6.10-relayfs-ltt/include/asm-ppc/ltt.h --- linux-2.6.10-relayfs/include/asm-ppc/ltt.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/include/asm-ppc/ltt.h 2005-01-13 22:21:44.000000000 -0500 @@ -0,0 +1,30 @@ +/* + * linux/include/asm-ppc/ltt.h + * + * Copyright (C) 2002, Karim Yaghmour + * + * PowerPC definitions for tracing system + */ + +#include +#include + +/* Current arch type */ +#define LTT_ARCH_TYPE LTT_ARCH_TYPE_PPC + +/* PowerPC variants */ +#define LTT_ARCH_VARIANT_PPC_4xx 1 /* 4xx systems (IBM embedded series) */ +#define LTT_ARCH_VARIANT_PPC_6xx 2 /* 6xx/7xx/74xx/8260/POWER3 systems (desktop flavor) */ +#define LTT_ARCH_VARIANT_PPC_8xx 3 /* 8xx system (Motoral embedded series) */ +#define LTT_ARCH_VARIANT_PPC_ISERIES 4 /* 8xx system (iSeries) */ + +/* Current variant type */ +#if defined(CONFIG_4xx) +#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_PPC_4xx +#elif defined(CONFIG_6xx) +#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_PPC_6xx +#elif defined(CONFIG_8xx) +#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_PPC_8xx +#elif defined(CONFIG_PPC_ISERIES) +#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_PPC_ISERIES +#endif diff -urpN linux-2.6.10-relayfs/include/asm-s390/ltt.h linux-2.6.10-relayfs-ltt/include/asm-s390/ltt.h --- linux-2.6.10-relayfs/include/asm-s390/ltt.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/include/asm-s390/ltt.h 2005-01-13 22:21:44.000000000 -0500 @@ -0,0 +1,15 @@ +/* + * linux/include/asm-s390/ltt.h + * + * Copyright (C) 2002, Karim Yaghmour + * + * S/390 definitions for tracing system + */ + +#include + +/* Current arch type */ +#define LTT_ARCH_TYPE LTT_ARCH_TYPE_S390 + +/* Current variant type */ +#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE diff -urpN linux-2.6.10-relayfs/include/asm-sh/ltt.h linux-2.6.10-relayfs-ltt/include/asm-sh/ltt.h --- linux-2.6.10-relayfs/include/asm-sh/ltt.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/include/asm-sh/ltt.h 2005-01-13 22:21:44.000000000 -0500 @@ -0,0 +1,15 @@ +/* + * linux/include/asm-sh/ltt.h + * + * Copyright (C) 2002, Karim Yaghmour + * + * SuperH definitions for tracing system + */ + +#include + +/* Current arch type */ +#define LTT_ARCH_TYPE LTT_ARCH_TYPE_SH + +/* Current variant type */ +#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE diff -urpN linux-2.6.10-relayfs/include/linux/ltt-core.h linux-2.6.10-relayfs-ltt/include/linux/ltt-core.h --- linux-2.6.10-relayfs/include/linux/ltt-core.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/include/linux/ltt-core.h 2005-01-13 22:21:56.000000000 -0500 @@ -0,0 +1,430 @@ +/* + * linux/include/linux/ltt-core.h + * + * Copyright (C) 1999-2004 Karim Yaghmour (karim@opersys.com) + * + * This contains the core definitions for the Linux Trace Toolkit. + */ + +#ifndef _LTT_CORE_H +#define _LTT_CORE_H + +#include +#include + +#include + +/* Is kernel tracing enabled */ +#if defined(CONFIG_LTT) + +#define LTT_CUSTOM_EV_MAX_SIZE 8192 +#define LTT_CUSTOM_EV_TYPE_STR_LEN 20 +#define LTT_CUSTOM_EV_DESC_STR_LEN 100 +#define LTT_CUSTOM_EV_FORM_STR_LEN 256 +#define LTT_CUSTOM_EV_FINAL_STR_LEN 200 + +#define LTT_CUSTOM_EV_FORMAT_TYPE_NONE 0 +#define LTT_CUSTOM_EV_FORMAT_TYPE_STR 1 +#define LTT_CUSTOM_EV_FORMAT_TYPE_HEX 2 +#define LTT_CUSTOM_EV_FORMAT_TYPE_XML 3 +#define LTT_CUSTOM_EV_FORMAT_TYPE_IBM 4 + +#define LTT_MAX_HANDLES 256 + +/* In the ltt root directory lives the trace control file, used for + kernel-user communication. */ +#define LTT_RELAYFS_ROOT "ltt" +#define LTT_CONTROL_FILE "control" + +/* We currently support 2 traces, normal trace and flight recorder */ +#define NR_TRACES 2 +#define TRACE_HANDLE 0 +#define FLIGHT_HANDLE 1 + +/* System types */ +#define LTT_SYS_TYPE_VANILLA_LINUX 1 + +/* Architecture types */ +#define LTT_ARCH_TYPE_I386 1 +#define LTT_ARCH_TYPE_PPC 2 +#define LTT_ARCH_TYPE_SH 3 +#define LTT_ARCH_TYPE_S390 4 +#define LTT_ARCH_TYPE_MIPS 5 +#define LTT_ARCH_TYPE_ARM 6 + +/* Standard definitions for variants */ +#define LTT_ARCH_VARIANT_NONE 0 /* Main architecture implementation */ + +typedef u64 ltt_event_mask; + +/* Per-CPU channel information */ +struct ltt_channel_data +{ + int channel_handle; + struct rchan_reader *reader; + atomic_t waiting_for_cpu_async; + u32 events_lost; +}; + +/* Per-trace status info */ +struct ltt_trace_info +{ + int active; + unsigned int trace_handle; + int paused; + int flight_recorder; + int use_locking; + int using_tsc; + u32 n_buffers; + u32 buf_size; + ltt_event_mask traced_events; + ltt_event_mask log_event_details_mask; + u32 buffers_produced[NR_CPUS]; +}; + +/* Status info for all traces */ +struct ltt_tracer_status +{ + int num_cpus; + struct ltt_trace_info traces[NR_TRACES]; +}; + +/* Per-trace information - each trace/flight recorder represented by one */ +struct ltt_trace_struct +{ + unsigned int trace_handle; /* For convenience */ + struct ltt_trace_struct *active; /* 'this' if active, or NULL */ + int paused; /* Not currently logging */ + struct ltt_channel_data relay_data[NR_CPUS];/* Relayfs handles, by CPU */ + int flight_recorder;/* i.e. this is not a trace */ + struct task_struct *daemon_task_struct;/* Daemon associated with trace */ + struct _ltt_trace_start *trace_start_data; /* Trace start event data, for flight recorder */ + int tracer_started; + int tracer_stopping; + struct proc_dir_entry *proc_dir_entry; /* proc/ltt/0..1 */ + ltt_event_mask traced_events; + ltt_event_mask log_event_details_mask; + u32 n_buffers; /* Number of sub-buffers */ + u32 buf_size; /* Size of sub-buffer */ + int use_locking; + int using_tsc; + int log_cpuid; + int tracing_pid; + int tracing_pgrp; + int tracing_gid; + int tracing_uid; + pid_t traced_pid; + pid_t traced_pgrp; + gid_t traced_gid; + uid_t traced_uid; + unsigned long buffer_switches_pending;/* For trace */ + struct work_struct work; /* stop work struct */ +}; + +extern int ltt_set_trace_config( + int do_syscall_depth, + int do_syscall_bounds, + int eip_depth, + void *eip_lower_bound, + void *eip_upper_bound); +extern void ltt_set_flight_recorder_config( + struct ltt_trace_struct *trace); +extern int ltt_get_trace_config( + int *do_syscall_depth, + int *do_syscall_bounds, + int *eip_depth, + void **eip_lower_bound, + void **eip_upper_bound); +extern int ltt_get_status( + struct ltt_tracer_status *tracer_status); +extern int ltt_create_event( + char *event_type, + char *event_desc, + int format_type, + char *format_data); +extern int ltt_create_owned_event( + char *event_type, + char *event_desc, + int format_type, + char *format_data, + pid_t owner_pid); +extern void ltt_destroy_event( + int event_id); +extern void ltt_destroy_owners_events( + pid_t owner_pid); +extern void ltt_reregister_custom_events(void); +extern int ltt_log_std_formatted_event( + int event_id, + ...); +extern int ltt_log_raw_event( + int event_id, + int event_size, + void *event_data); +extern int _ltt_log_event( + struct ltt_trace_struct *trace, + u8 event_id, + void *event_struct, + u8 cpu_id); +extern int ltt_log_event( + u8 event_id, + void *event_struct); +extern int ltt_valid_trace_handle( + unsigned int tracer_handle); +extern int ltt_alloc_trace_handle( + unsigned int tracer_handle); +extern int ltt_free_trace_handle( + unsigned int tracer_handle); +extern int ltt_free_daemon_handle( + struct ltt_trace_struct *trace); +extern void ltt_free_all_handles( + struct task_struct* task_ptr); +extern int ltt_set_buffer_size( + struct ltt_trace_struct *trace, + int buffers_size, + char *dirname); +extern int ltt_set_n_buffers( + struct ltt_trace_struct *trace, + int no_buffers); +extern int ltt_set_default_config( + struct ltt_trace_struct *trace); +extern int ltt_syscall_active( + int syscall_type); +extern void ltt_flight_pause( + void); +extern void ltt_flight_unpause( + void); + +/* Tracer properties */ +#define LTT_TRACER_DEFAULT_BUF_SIZE 50000 +#define LTT_TRACER_MIN_BUF_SIZE 1000 +#define LTT_TRACER_MAX_BUF_SIZE 500000 +#define LTT_TRACER_MIN_BUFFERS 2 +#define LTT_TRACER_MAX_BUFFERS 256 +#define LTT_TRACER_MAGIC_NUMBER 0x00D6B7ED +#define LTT_TRACER_VERSION_MAJOR 2 +#define LTT_TRACER_VERSION_MINOR 2 + +#define LTT_TRACER_FIRST_EVENT_SIZE (sizeof(u8) + sizeof(u32) + sizeof(ltt_buffer_start) + sizeof(uint16_t)) +#define LTT_TRACER_START_TRACE_EVENT_SIZE (sizeof(u8) + sizeof(u32) + sizeof(ltt_trace_start) + sizeof(uint16_t)) +#define LTT_TRACER_LAST_EVENT_SIZE (sizeof(u8) \ + + sizeof(u8) \ + + sizeof(u32) \ + + sizeof(ltt_buffer_end) \ + + sizeof(uint16_t) \ + + sizeof(u32)) + +/* The configurations possible */ +enum { + LTT_TRACER_START = LTT_TRACER_MAGIC_NUMBER, /* Start tracing events using the current configuration */ + LTT_TRACER_STOP, /* Stop tracing */ + LTT_TRACER_CONFIG_DEFAULT, /* Set the tracer to the default configuration */ + LTT_TRACER_CONFIG_MEMORY_BUFFERS, /* Set the memory buffers the daemon wants us to use */ + LTT_TRACER_CONFIG_EVENTS, /* Trace the given events */ + LTT_TRACER_CONFIG_DETAILS, /* Record the details of the event, or not */ + LTT_TRACER_CONFIG_CPUID, /* Record the CPUID associated with the event */ + LTT_TRACER_CONFIG_PID, /* Trace only one process */ + LTT_TRACER_CONFIG_PGRP, /* Trace only the given process group */ + LTT_TRACER_CONFIG_GID, /* Trace the processes of a given group of users */ + LTT_TRACER_CONFIG_UID, /* Trace the processes of a given user */ + LTT_TRACER_CONFIG_SYSCALL_EIP_DEPTH, /* Set the call depth at which the EIP should be fetched on syscall */ + LTT_TRACER_CONFIG_SYSCALL_EIP_LOWER, /* Set the lowerbound address from which EIP is recorded on syscall */ + LTT_TRACER_CONFIG_SYSCALL_EIP_UPPER, /* Set the upperbound address from which EIP is recorded on syscall */ + LTT_TRACER_DATA_COMITTED, /* The daemon has comitted the last trace */ + LTT_TRACER_GET_EVENTS_LOST, /* Get the number of events lost */ + LTT_TRACER_CREATE_USER_EVENT, /* Create a user tracable event */ + LTT_TRACER_DESTROY_USER_EVENT, /* Destroy a user tracable event */ + LTT_TRACER_TRACE_USER_EVENT, /* Trace a user event */ + LTT_TRACER_SET_EVENT_MASK, /* Set the trace event mask */ + LTT_TRACER_GET_EVENT_MASK, /* Get the trace event mask */ + LTT_TRACER_GET_BUFFER_CONTROL, /* Get the buffer control data for the lockless schem*/ + LTT_TRACER_CONFIG_N_MEMORY_BUFFERS, /* Set the number of memory buffers the daemon wants us to use */ + LTT_TRACER_CONFIG_USE_LOCKING, /* Set the locking scheme to use */ + LTT_TRACER_CONFIG_TIMESTAMP, /* Set the timestamping method to use */ + LTT_TRACER_GET_ARCH_INFO, /* Get information about the CPU configuration */ + LTT_TRACER_ALLOC_HANDLE, /* Allocate a tracer handle */ + LTT_TRACER_FREE_HANDLE, /* Free a single handle */ + LTT_TRACER_FREE_DAEMON_HANDLE, /* Free the daemon's handle */ + LTT_TRACER_FREE_ALL_HANDLES, /* Free all handles */ + LTT_TRACER_MAP_BUFFER, /* Map buffer to process-space */ + LTT_TRACER_PAUSE, /* Pause tracing */ + LTT_TRACER_UNPAUSE, /* Unpause tracing */ + LTT_TRACER_GET_START_INFO, /* trace start data */ + LTT_TRACER_GET_STATUS /* status of traces */ +}; + +/* Lockless scheme definitions */ +#define LTT_TRACER_LOCKLESS_MIN_BUF_SIZE LTT_CUSTOM_EV_MAX_SIZE + 8192 +#define LTT_TRACER_LOCKLESS_MAX_BUF_SIZE 0x1000000 + +/* Flags used for per-CPU tasks */ +#define LTT_NOTHING_TO_DO 0x00 +#define LTT_FINALIZE_TRACE 0x02 +#define LTT_TRACE_HEARTBEAT 0x08 + +/* How often the LTT per-CPU timers fire */ +#define LTT_PERCPU_TIMER_FREQ (HZ/10); + +/* Convenience accessors */ +#define waiting_for_cpu_async(trace_handle, cpu) (current_traces[trace_handle].relay_data[cpu].waiting_for_cpu_async) +#define trace_channel_handle(trace_handle, cpu) (current_traces[trace_handle].relay_data[cpu].channel_handle) +#define trace_channel_reader(trace_handle, cpu) (current_traces[trace_handle].relay_data[cpu].reader) +#define trace_buffers_full(cpu) (daemon_relay_data[cpu].buffers_full) +#define events_lost(trace_handle, cpu) (current_traces[trace_handle].relay_data[cpu].events_lost) + +/* Used for sharing per-buffer information between driver and daemon */ +struct ltt_buf_control_info +{ + s16 cpu_id; + u32 buffer_switches_pending; + u32 buffer_control_valid; + + u32 buf_size; + u32 n_buffers; + u32 cur_idx; + u32 buffers_produced; + u32 buffers_consumed; + int buffer_complete[LTT_TRACER_MAX_BUFFERS]; +}; + +/* Used for sharing buffer-commit information between driver and daemon */ +struct ltt_buffers_committed +{ + u8 cpu_id; + u32 buffers_consumed; +}; + +/* Used for specifying size/cpu id pair between driver and daemon */ +struct ltt_cpu_mmap_data +{ + u8 cpu_id; + unsigned long map_size; +}; + +/* Used for sharing architecture-specific info between driver and daemon */ +struct ltt_arch_info +{ + int n_cpus; + int page_shift; +}; + +extern __inline__ int ltt_set_bit(int nr, void *addr) +{ + unsigned char *p = addr; + unsigned char mask = 1 << (nr & 7); + unsigned char old; + + p += nr >> 3; + old = *p; + *p |= mask; + + return ((old & mask) != 0); +} + +extern __inline__ int ltt_clear_bit(int nr, void *addr) +{ + unsigned char *p = addr; + unsigned char mask = 1 << (nr & 7); + unsigned char old; + + p += nr >> 3; + old = *p; + *p &= ~mask; + + return ((old & mask) != 0); +} + +extern __inline__ int ltt_test_bit(int nr, void *addr) +{ + unsigned char *p = addr; + unsigned char mask = 1 << (nr & 7); + + p += nr >> 3; + + return ((*p & mask) != 0); +} + +#if !defined(CONFIG_X86) +# define cpu_has_tsc 0 /* FIXME: cpu_has_tsc isn't set except on x86 */ +#endif + +/** + * switch_time_delta: - Utility function getting buffer switch time delta. + * @time_delta: previously calculated or retrieved time delta + * + * Returns the time_delta passed in if we're using TSC or 0 otherwise. + */ +static inline u32 switch_time_delta(u32 time_delta, + int using_tsc) +{ + if((using_tsc == 1) && cpu_has_tsc) + return time_delta; + else + return 0; +} + +#else /* defined(CONFIG_LTT) */ +static inline int ltt_create_event(char *event_type, + char *event_desc, + int format_type, + char *format_data) +{ + return 0; +} + +static inline int ltt_create_owned_event(char *event_type, + char *event_desc, + int format_type, + char *format_data, + pid_t owner_pid) +{ + return 0; +} + +static inline void ltt_destroy_event(int event_id) +{ +} + +static inline void ltt_destroy_owners_events(pid_t owner_pid) +{ +} + +static inline void ltt_reregister_custom_events(void) +{ +} + +static inline int ltt_log_std_formatted_event(int event_id, ...) +{ + return 0; +} + + +static inline int ltt_log_raw_event(int event_id, + int event_size, + void *event_data) +{ + return 0; +} + +static inline int _ltt_log_event(u8 event_id, + void *event_struct, + u8 cpu_id) +{ + return 0; +} + +static inline int ltt_log_event(u8 event_id, + void *event_struct) +{ + return 0; +} + +static inline void ltt_flight_pause(void) +{ +} + +static inline void ltt_flight_unpause(void) +{ +} + +#endif /* defined(CONFIG_LTT) */ +#endif /* _LTT_CORE_H */ diff -urpN linux-2.6.10-relayfs/include/linux/ltt-events.h linux-2.6.10-relayfs-ltt/include/linux/ltt-events.h --- linux-2.6.10-relayfs/include/linux/ltt-events.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/include/linux/ltt-events.h 2005-01-13 22:21:56.000000000 -0500 @@ -0,0 +1,424 @@ +/* + * linux/include/linux/ltt-events.h + * + * Copyright (C) 1999-2004 Karim Yaghmour (karim@opersys.com) + * + * This contains the event definitions for the Linux Trace Toolkit. + */ + +#ifndef _LTT_EVENTS_H +#define _LTT_EVENTS_H + +#include +#include + +/* Is kernel tracing enabled */ +#if defined(CONFIG_LTT) + +/* Don't set this to "1" unless you really know what you're doing */ +#define LTT_UNPACKED_STRUCTS 0 + +/* Structure packing within the trace */ +#if LTT_UNPACKED_STRUCTS +#define LTT_PACKED_STRUCT +#else +#define LTT_PACKED_STRUCT __attribute__ ((packed)) +#endif + +extern unsigned int ltt_syscall_entry_trace_active; +extern unsigned int ltt_syscall_exit_trace_active; + +static inline void ltt_ev(u8 event_id, void* data) +{ + ltt_log_event(event_id, data); +} + +/* Traced events */ +enum { + LTT_EV_START = 0, /* This is to mark the trace's start */ + LTT_EV_SYSCALL_ENTRY, /* Entry in a given system call */ + LTT_EV_SYSCALL_EXIT, /* Exit from a given system call */ + LTT_EV_TRAP_ENTRY, /* Entry in a trap */ + LTT_EV_TRAP_EXIT, /* Exit from a trap */ + LTT_EV_IRQ_ENTRY, /* Entry in an irq */ + LTT_EV_IRQ_EXIT, /* Exit from an irq */ + LTT_EV_SCHEDCHANGE, /* Scheduling change */ + LTT_EV_KERNEL_TIMER, /* The kernel timer routine has been called */ + LTT_EV_SOFT_IRQ, /* Hit key part of soft-irq management */ + LTT_EV_PROCESS, /* Hit key part of process management */ + LTT_EV_FILE_SYSTEM, /* Hit key part of file system */ + LTT_EV_TIMER, /* Hit key part of timer management */ + LTT_EV_MEMORY, /* Hit key part of memory management */ + LTT_EV_SOCKET, /* Hit key part of socket communication */ + LTT_EV_IPC, /* Hit key part of System V IPC */ + LTT_EV_NETWORK, /* Hit key part of network communication */ + LTT_EV_BUFFER_START, /* Mark the begining of a trace buffer */ + LTT_EV_BUFFER_END, /* Mark the ending of a trace buffer */ + LTT_EV_NEW_EVENT, /* New event type */ + LTT_EV_CUSTOM, /* Custom event */ + LTT_EV_CHANGE_MASK, /* Change in event mask */ + LTT_EV_HEARTBEAT /* Heartbeat event */ +}; + +/* Number of traced events */ +#define LTT_EV_MAX LTT_EV_HEARTBEAT + +/* Information logged when a trace is started */ +typedef struct _ltt_trace_start { + u32 magic_number; + u32 arch_type; + u32 arch_variant; + u32 system_type; + u8 major_version; + u8 minor_version; + + u32 buffer_size; + ltt_event_mask event_mask; + ltt_event_mask details_mask; + u8 log_cpuid; + u8 use_tsc; + u8 flight_recorder; +} LTT_PACKED_STRUCT ltt_trace_start; + +/* LTT_SYSCALL_ENTRY */ +typedef struct _ltt_syscall_entry { + u8 syscall_id; /* Syscall entry number in entry.S */ + u32 address; /* Address from which call was made */ +} LTT_PACKED_STRUCT ltt_syscall_entry; + +/* LTT_TRAP_ENTRY */ +#ifndef __s390__ +typedef struct _ltt_trap_entry { + u16 trap_id; /* Trap number */ + u32 address; /* Address where trap occured */ +} LTT_PACKED_STRUCT ltt_trap_entry; +static inline void ltt_ev_trap_entry(u16 trap_id, u32 address) +#else +typedef u64 trapid_t; +typedef struct _ltt_trap_entry { + trapid_t trap_id; /* Trap number */ + u32 address; /* Address where trap occured */ +} LTT_PACKED_STRUCT ltt_trap_entry; +static inline void ltt_ev_trap_entry(trapid_t trap_id, u32 address) +#endif +{ + ltt_trap_entry trap_event; + + trap_event.trap_id = trap_id; + trap_event.address = address; + + ltt_log_event(LTT_EV_TRAP_ENTRY, &trap_event); +} + +/* LTT_TRAP_EXIT */ +static inline void ltt_ev_trap_exit(void) +{ + ltt_log_event(LTT_EV_TRAP_EXIT, NULL); +} + +/* LTT_IRQ_ENTRY */ +typedef struct _ltt_irq_entry { + u8 irq_id; /* IRQ number */ + u8 kernel; /* Are we executing kernel code */ +} LTT_PACKED_STRUCT ltt_irq_entry; +static inline void ltt_ev_irq_entry(u8 irq_id, u8 in_kernel) +{ + ltt_irq_entry irq_entry; + + irq_entry.irq_id = irq_id; + irq_entry.kernel = in_kernel; + + ltt_log_event(LTT_EV_IRQ_ENTRY, &irq_entry); +} + +/* LTT_IRQ_EXIT */ +static inline void ltt_ev_irq_exit(void) +{ + ltt_log_event(LTT_EV_IRQ_EXIT, NULL); +} + +/* LTT_SCHEDCHANGE */ +typedef struct _ltt_schedchange { + u32 out; /* Outgoing process */ + u32 in; /* Incoming process */ + u32 out_state; /* Outgoing process' state */ +} LTT_PACKED_STRUCT ltt_schedchange; +static inline void ltt_ev_schedchange(task_t * task_out, task_t * task_in) +{ + ltt_schedchange sched_event; + + sched_event.out = (u32) task_out->pid; + sched_event.in = (u32) task_in; + sched_event.out_state = (u32) task_out->state; + + ltt_log_event(LTT_EV_SCHEDCHANGE, &sched_event); +} + +/* LTT_SOFT_IRQ */ +enum { + LTT_EV_SOFT_IRQ_BOTTOM_HALF = 1, /* Conventional bottom-half */ + LTT_EV_SOFT_IRQ_SOFT_IRQ, /* Real soft-irq */ + LTT_EV_SOFT_IRQ_TASKLET_ACTION, /* Tasklet action */ + LTT_EV_SOFT_IRQ_TASKLET_HI_ACTION /* Tasklet hi-action */ +}; +typedef struct _ltt_soft_irq { + u8 event_sub_id; /* Soft-irq event Id */ + u32 event_data; +} LTT_PACKED_STRUCT ltt_soft_irq; +static inline void ltt_ev_soft_irq(u8 ev_id, u32 data) +{ + ltt_soft_irq soft_irq_event; + + soft_irq_event.event_sub_id = ev_id; + soft_irq_event.event_data = data; + + ltt_log_event(LTT_EV_SOFT_IRQ, &soft_irq_event); +} + +/* LTT_PROCESS */ +enum { + LTT_EV_PROCESS_KTHREAD = 1, /* Creation of a kernel thread */ + LTT_EV_PROCESS_FORK, /* A fork or clone occured */ + LTT_EV_PROCESS_EXIT, /* An exit occured */ + LTT_EV_PROCESS_WAIT, /* A wait occured */ + LTT_EV_PROCESS_SIGNAL, /* A signal has been sent */ + LTT_EV_PROCESS_WAKEUP /* Wake up a process */ +}; +typedef struct _ltt_process { + u8 event_sub_id; /* Process event ID */ + u32 event_data1; + u32 event_data2; +} LTT_PACKED_STRUCT ltt_process; +static inline void ltt_ev_process(u8 ev_id, u32 data1, u32 data2) +{ + ltt_process proc_event; + + proc_event.event_sub_id = ev_id; + proc_event.event_data1 = data1; + proc_event.event_data2 = data2; + + ltt_log_event(LTT_EV_PROCESS, &proc_event); +} +static inline void ltt_ev_process_exit(u32 data1, u32 data2) +{ + ltt_process proc_event; + + proc_event.event_sub_id = LTT_EV_PROCESS_EXIT; + + /**** WARNING ****/ + /* Regardless of whether this trace statement is active or not, these + two function must be called, otherwise there will be inconsistencies + in the kernel's structures. */ + ltt_destroy_owners_events(current->pid); + ltt_free_all_handles(current); + + ltt_log_event(LTT_EV_PROCESS, &proc_event); +} + +/* LTT_FILE_SYSTEM */ +enum { + LTT_EV_FILE_SYSTEM_BUF_WAIT_START = 1, /* Starting to wait for a data buffer */ + LTT_EV_FILE_SYSTEM_BUF_WAIT_END, /* End to wait for a data buffer */ + LTT_EV_FILE_SYSTEM_EXEC, /* An exec occured */ + LTT_EV_FILE_SYSTEM_OPEN, /* An open occured */ + LTT_EV_FILE_SYSTEM_CLOSE, /* A close occured */ + LTT_EV_FILE_SYSTEM_READ, /* A read occured */ + LTT_EV_FILE_SYSTEM_WRITE, /* A write occured */ + LTT_EV_FILE_SYSTEM_SEEK, /* A seek occured */ + LTT_EV_FILE_SYSTEM_IOCTL, /* An ioctl occured */ + LTT_EV_FILE_SYSTEM_SELECT, /* A select occured */ + LTT_EV_FILE_SYSTEM_POLL /* A poll occured */ +}; +typedef struct _ltt_file_system { + u8 event_sub_id; /* File system event ID */ + u32 event_data1; + u32 event_data2; + char *file_name; /* Name of file operated on */ +} LTT_PACKED_STRUCT ltt_file_system; +static inline void ltt_ev_file_system(u8 ev_id, u32 data1, u32 data2, const unsigned char *file_name) +{ + ltt_file_system fs_event; + + fs_event.event_sub_id = ev_id; + fs_event.event_data1 = data1; + fs_event.event_data2 = data2; + fs_event.file_name = (char*) file_name; + + ltt_log_event(LTT_EV_FILE_SYSTEM, &fs_event); +} + +/* LTT_TIMER */ +enum { + LTT_EV_TIMER_EXPIRED = 1, /* Timer expired */ + LTT_EV_TIMER_SETITIMER, /* Setting itimer occurred */ + LTT_EV_TIMER_SETTIMEOUT /* Setting sched timeout occurred */ +}; +typedef struct _ltt_timer { + u8 event_sub_id; /* Timer event ID */ + u8 event_sdata; /* Short data */ + u32 event_data1; + u32 event_data2; +} LTT_PACKED_STRUCT ltt_timer; +static inline void ltt_ev_timer(u8 ev_id, u8 sdata, u32 data1, u32 data2) +{ + ltt_timer timer_event; + + timer_event.event_sub_id = ev_id; + timer_event.event_sdata = sdata; + timer_event.event_data1 = data1; + timer_event.event_data2 = data2; + + ltt_log_event(LTT_EV_TIMER, &timer_event); +} + +/* LTT_MEMORY */ +enum { + LTT_EV_MEMORY_PAGE_ALLOC = 1, /* Allocating pages */ + LTT_EV_MEMORY_PAGE_FREE, /* Freing pages */ + LTT_EV_MEMORY_SWAP_IN, /* Swaping pages in */ + LTT_EV_MEMORY_SWAP_OUT, /* Swaping pages out */ + LTT_EV_MEMORY_PAGE_WAIT_START, /* Start to wait for page */ + LTT_EV_MEMORY_PAGE_WAIT_END /* End to wait for page */ +}; +typedef struct _ltt_memory { + u8 event_sub_id; /* Memory event ID */ + u32 event_data; +} LTT_PACKED_STRUCT ltt_memory; +static inline void ltt_ev_memory(u8 ev_id, u32 data) +{ + ltt_memory memory_event; + + memory_event.event_sub_id = ev_id; + memory_event.event_data = data; + + ltt_log_event(LTT_EV_MEMORY, &memory_event); +} + +/* LTT_SOCKET */ +enum { + LTT_EV_SOCKET_CALL = 1, /* A socket call occured */ + LTT_EV_SOCKET_CREATE, /* A socket has been created */ + LTT_EV_SOCKET_SEND, /* Data was sent to a socket */ + LTT_EV_SOCKET_RECEIVE /* Data was read from a socket */ +}; +typedef struct _ltt_socket { + u8 event_sub_id; /* Socket event ID */ + u32 event_data1; + u32 event_data2; +} LTT_PACKED_STRUCT ltt_socket; +static inline void ltt_ev_socket(u8 ev_id, u32 data1, u32 data2) +{ + ltt_socket socket_event; + + socket_event.event_sub_id = ev_id; + socket_event.event_data1 = data1; + socket_event.event_data2 = data2; + + ltt_log_event(LTT_EV_SOCKET, &socket_event); +} + +/* LTT_IPC */ +enum { + LTT_EV_IPC_CALL = 1, /* A System V IPC call occured */ + LTT_EV_IPC_MSG_CREATE, /* A message queue has been created */ + LTT_EV_IPC_SEM_CREATE, /* A semaphore was created */ + LTT_EV_IPC_SHM_CREATE /* A shared memory segment has been created */ +}; +typedef struct _ltt_ipc { + u8 event_sub_id; /* IPC event ID */ + u32 event_data1; + u32 event_data2; +} LTT_PACKED_STRUCT ltt_ipc; +static inline void ltt_ev_ipc(u8 ev_id, u32 data1, u32 data2) +{ + ltt_ipc ipc_event; + + ipc_event.event_sub_id = ev_id; + ipc_event.event_data1 = data1; + ipc_event.event_data2 = data2; + + ltt_log_event(LTT_EV_IPC, &ipc_event); +} + +/* LTT_NETWORK */ +enum { + LTT_EV_NETWORK_PACKET_IN = 1, /* A packet came in */ + LTT_EV_NETWORK_PACKET_OUT /* A packet was sent */ +}; +typedef struct _ltt_network { + u8 event_sub_id; /* Network event ID */ + u32 event_data; +} LTT_PACKED_STRUCT ltt_network; +static inline void ltt_ev_network(u8 ev_id, u32 data) +{ + ltt_network net_event; + + net_event.event_sub_id = ev_id; + net_event.event_data = data; + + ltt_log_event(LTT_EV_NETWORK, &net_event); +} + +/* Start of trace buffer information */ +typedef struct _ltt_buffer_start { + struct timeval time; /* Time stamp of this buffer */ + u32 tsc; /* TSC of this buffer, if applicable */ + u32 id; /* Unique buffer ID */ +} LTT_PACKED_STRUCT ltt_buffer_start; + +/* End of trace buffer information */ +typedef struct _ltt_buffer_end { + struct timeval time; /* Time stamp of this buffer */ + u32 tsc; /* TSC of this buffer, if applicable */ +} LTT_PACKED_STRUCT ltt_buffer_end; + +/* Custom declared events */ +/* ***WARNING*** These structures should never be used as is, use the + provided custom event creation and logging functions. */ +typedef struct _ltt_new_event { + /* Basics */ + u32 id; /* Custom event ID */ + char type[LTT_CUSTOM_EV_TYPE_STR_LEN]; /* Event type description */ + char desc[LTT_CUSTOM_EV_DESC_STR_LEN]; /* Detailed event description */ + + /* Custom formatting */ + u32 format_type; /* Type of formatting */ + char form[LTT_CUSTOM_EV_FORM_STR_LEN]; /* Data specific to format */ +} LTT_PACKED_STRUCT ltt_new_event; +typedef struct _ltt_custom { + u32 id; /* Event ID */ + u32 data_size; /* Size of data recorded by event */ + void *data; /* Data recorded by event */ +} LTT_PACKED_STRUCT ltt_custom; + +/* LTT_CHANGE_MASK */ +typedef struct _ltt_change_mask { + ltt_event_mask mask; /* Event mask */ +} LTT_PACKED_STRUCT ltt_change_mask; + + +/* LTT_HEARTBEAT */ +static inline void ltt_ev_heartbeat(void) +{ + ltt_log_event(LTT_EV_HEARTBEAT, NULL); +} + +#else /* defined(CONFIG_LTT) */ +#define ltt_ev(ID, DATA) +#define ltt_ev_trap_entry(ID, EIP) +#define ltt_ev_trap_exit() +#define ltt_ev_irq_entry(ID, KERNEL) +#define ltt_ev_irq_exit() +#define ltt_ev_schedchange(OUT, IN) +#define ltt_ev_soft_irq(ID, DATA) +#define ltt_ev_process(ID, DATA1, DATA2) +#define ltt_ev_process_exit(DATA1, DATA2) +#define ltt_ev_file_system(ID, DATA1, DATA2, FILE_NAME) +#define ltt_ev_timer(ID, SDATA, DATA1, DATA2) +#define ltt_ev_memory(ID, DATA) +#define ltt_ev_socket(ID, DATA1, DATA2) +#define ltt_ev_ipc(ID, DATA1, DATA2) +#define ltt_ev_network(ID, DATA) +#define ltt_ev_heartbeat() +#endif /* defined(CONFIG_LTT) */ +#endif /* _LTT_EVENTS_H */ diff -urpN linux-2.6.10-relayfs/init/Kconfig linux-2.6.10-relayfs-ltt/init/Kconfig --- linux-2.6.10-relayfs/init/Kconfig 2004-12-24 16:35:24.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/init/Kconfig 2005-01-13 22:21:56.000000000 -0500 @@ -315,6 +315,38 @@ config CC_OPTIMIZE_FOR_SIZE If unsure, say N. +config LTT + bool "Linux Trace Toolkit support" + depends on RELAYFS_FS=y + default n + ---help--- + It is possible for the kernel to log important events to a trace + facility. 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 tracer that keeps the events in a data buffer (uses + relayfs). + 3) A trace daemon that interacts with the tracer and is + notified every time there is a certain quantity of data to + read from the tracer. + 4) A trace event data decoder that reads the accumulated data + and formats it in a human-readable format. + + If you say Y, the first two components will be built into the kernel. + Critical parts of the kernel will call upon the kernel tracing + function. The data is then recorded by the tracer if a trace daemon + is running in user-space and has issued a "start" command. + + In order to enable LTT support you must first select relayfs as + built-in. + + For more information on kernel tracing, the trace daemon or the event + decoder, please check the following address : + http://www.opersys.com/ltt + config SHMEM default y bool "Use full shmem filesystem" if EMBEDDED && MMU diff -urpN linux-2.6.10-relayfs/ipc/msg.c linux-2.6.10-relayfs-ltt/ipc/msg.c --- linux-2.6.10-relayfs/ipc/msg.c 2004-12-24 16:33:48.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/ipc/msg.c 2005-01-13 22:21:51.000000000 -0500 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "util.h" @@ -229,6 +230,7 @@ asmlinkage long sys_msgget (key_t key, i msg_unlock(msq); } up(&msg_ids.sem); + ltt_ev_ipc(LTT_EV_IPC_MSG_CREATE, ret, msgflg); return ret; } diff -urpN linux-2.6.10-relayfs/ipc/sem.c linux-2.6.10-relayfs-ltt/ipc/sem.c --- linux-2.6.10-relayfs/ipc/sem.c 2004-12-24 16:34:31.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/ipc/sem.c 2005-01-13 22:21:51.000000000 -0500 @@ -72,6 +72,7 @@ #include #include #include +#include #include #include "util.h" @@ -239,6 +240,7 @@ asmlinkage long sys_semget (key_t key, i } up(&sem_ids.sem); + ltt_ev_ipc(LTT_EV_IPC_SEM_CREATE, err, semflg); return err; } diff -urpN linux-2.6.10-relayfs/ipc/shm.c linux-2.6.10-relayfs-ltt/ipc/shm.c --- linux-2.6.10-relayfs/ipc/shm.c 2004-12-24 16:34:45.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/ipc/shm.c 2005-01-13 22:21:51.000000000 -0500 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "util.h" @@ -277,7 +278,7 @@ asmlinkage long sys_shmget (key_t key, s shm_unlock(shp); } up(&shm_ids.sem); - + ltt_ev_ipc(LTT_EV_IPC_SHM_CREATE, err, shmflg); return err; } diff -urpN linux-2.6.10-relayfs/kernel/exit.c linux-2.6.10-relayfs-ltt/kernel/exit.c --- linux-2.6.10-relayfs/kernel/exit.c 2004-12-24 16:35:27.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/kernel/exit.c 2005-01-13 22:21:51.000000000 -0500 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -811,6 +812,8 @@ fastcall NORET_TYPE void do_exit(long co acct_process(code); __exit_mm(tsk); + ltt_ev_process_exit(0, 0); + exit_sem(tsk); __exit_files(tsk); __exit_fs(tsk); @@ -1316,6 +1319,8 @@ static long do_wait(pid_t pid, int optio struct task_struct *tsk; int flag, retval; + ltt_ev_process(LTT_EV_PROCESS_WAIT, pid, 0); + add_wait_queue(¤t->wait_chldexit,&wait); repeat: /* diff -urpN linux-2.6.10-relayfs/kernel/fork.c linux-2.6.10-relayfs-ltt/kernel/fork.c --- linux-2.6.10-relayfs/kernel/fork.c 2004-12-24 16:33:59.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/kernel/fork.c 2005-01-13 22:21:51.000000000 -0500 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -1159,6 +1160,8 @@ long do_fork(unsigned long clone_flags, ptrace_notify ((trace << 8) | SIGTRAP); } + ltt_ev_process(LTT_EV_PROCESS_FORK, p->pid, 0); + if (clone_flags & CLONE_VFORK) { wait_for_completion(&vfork); if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) diff -urpN linux-2.6.10-relayfs/kernel/irq/handle.c linux-2.6.10-relayfs-ltt/kernel/irq/handle.c --- linux-2.6.10-relayfs/kernel/irq/handle.c 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/kernel/irq/handle.c 2005-01-13 22:21:51.000000000 -0500 @@ -11,6 +11,7 @@ #include #include #include +#include #include "internals.h" @@ -91,6 +92,8 @@ fastcall int handle_IRQ_event(unsigned i { int ret, retval = 0, status = 0; + ltt_ev_irq_entry(irq, !(user_mode(regs))); + if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); @@ -106,6 +109,8 @@ fastcall int handle_IRQ_event(unsigned i add_interrupt_randomness(irq); local_irq_disable(); + ltt_ev_irq_exit(); + return retval; } diff -urpN linux-2.6.10-relayfs/kernel/itimer.c linux-2.6.10-relayfs-ltt/kernel/itimer.c --- linux-2.6.10-relayfs/kernel/itimer.c 2004-12-24 16:34:32.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/kernel/itimer.c 2005-01-13 22:21:51.000000000 -0500 @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -69,6 +70,8 @@ void it_real_fn(unsigned long __data) struct task_struct * p = (struct task_struct *) __data; unsigned long interval; + ltt_ev_timer(LTT_EV_TIMER_EXPIRED, 0, 0, 0); + send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p); interval = p->it_real_incr; if (interval) { @@ -88,6 +91,7 @@ int do_setitimer(int which, struct itime j = timeval_to_jiffies(&value->it_value); if (ovalue && (k = do_getitimer(which, ovalue)) < 0) return k; + ltt_ev_timer(LTT_EV_TIMER_SETITIMER, which, i, j); switch (which) { case ITIMER_REAL: del_timer_sync(¤t->real_timer); diff -urpN linux-2.6.10-relayfs/kernel/ltt-core.c linux-2.6.10-relayfs-ltt/kernel/ltt-core.c --- linux-2.6.10-relayfs/kernel/ltt-core.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/kernel/ltt-core.c 2005-01-13 23:32:45.000000000 -0500 @@ -0,0 +1,2505 @@ +/* + * ltt-core.c + * + * (C) Copyright, 1999, 2000, 2001, 2002, 2003, 2004 - + * Karim Yaghmour (karim@opersys.com) + * + * Contains the kernel code for the Linux Trace Toolkit. + * + * Author: + * Karim Yaghmour (karim@opersys.com) + * + * Changelog: + * 14/12/04, Renamed trace macros and variables to avoid namespace + * pollution (i.e. TRACE_XXX is now ltt_ev_xxx, etc.) + * 24/01/04, Revamped tracer to rely entirely on relayfs, no sys_trace. + * Renamed all relevant files and functions from trace* to ltt*. + * 14/03/03, Modified to use relayfs (zanussi@us.ibm.com) + * 15/10/02, Changed tracer from device to kernel subsystem and added + * custom trace system call (sys_trace). + * 01/10/02, Coding style change to fit with kernel coding style. + * 16/02/02, Added Tom Zanussi's implementation of K42's lockless logging. + * K42 tracing guru Robert Wisniewski participated in the + * discussions surrounding this implementation. A big thanks to + * the IBM folks. + * 03/12/01, Added user event support. + * 05/01/01, Modified PPC bit manipulation functions for x86 + * compatibility (andy_lowe@mvista.com). + * 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, Changing 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 10 + * milli-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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Tracer configuration */ +static int num_cpus; + +/* System call tracing behavior */ +unsigned int syscall_entry_trace_active = 0; +unsigned int syscall_exit_trace_active = 0; +static int use_syscall_eip_bounds; +static int lower_eip_bound_set; +static int upper_eip_bound_set; +static void* lower_eip_bound; +static void* upper_eip_bound; +static int fetch_syscall_eip_use_depth; +static int fetch_syscall_eip_use_bounds; +static void* syscall_lower_eip_bound; +static void* syscall_upper_eip_bound; +static int syscall_eip_depth; +static int syscall_eip_depth_set; + +/* Data buffer management */ +static struct ltt_trace_struct current_traces[NR_TRACES]; +static u32 start_reserve = LTT_TRACER_FIRST_EVENT_SIZE; +static u32 end_reserve = LTT_TRACER_LAST_EVENT_SIZE; +static u32 trace_start_reserve = LTT_TRACER_START_TRACE_EVENT_SIZE; +static struct ltt_arch_info ltt_arch_info; +static struct ltt_buf_control_info shared_buf_ctl; +static char * user_event_data = NULL; + +/* Relayfs interaction */ +static struct rchan_callbacks ltt_callbacks; /* relayfs callbacks */ +static char relay_file_name[PATH_MAX]; /* scratch area */ + +/* Timer management */ +static struct timer_list heartbeat_timer; +static struct timer_list percpu_timer[NR_CPUS] __cacheline_aligned; + +/* /proc variables */ +static struct proc_dir_entry * ltt_proc_root_entry; /* proc/ltt */ +static int tmp_rchan_handles[NR_CPUS]; +static char relayfs_path[PATH_MAX]; /* path to attribs */ +static int control_channel; /* LTT control channel */ + +/* Forward declarations */ +static struct proc_dir_entry *create_handle_proc_dir(unsigned trace_handle); +static void remove_handle_proc_dir(struct proc_dir_entry *handle_dir, + unsigned trace_handle); + +/* Size of statically defined events */ +int event_struct_size[LTT_EV_MAX + 1] = +{ + sizeof(ltt_trace_start), + sizeof(ltt_syscall_entry), + 0, /* LTT_SYSCALL_EXIT */ + sizeof(ltt_trap_entry), + 0, /* LTT_TRAP_EXIT */ + sizeof(ltt_irq_entry), + 0, /* LTT_IRQ_EXIT */ + sizeof(ltt_schedchange), + 0, /* LTT_KERNEL_TIMER */ + sizeof(ltt_soft_irq), + sizeof(ltt_process), + sizeof(ltt_file_system), + sizeof(ltt_timer), + sizeof(ltt_memory), + sizeof(ltt_socket), + sizeof(ltt_ipc), + sizeof(ltt_network), + sizeof(ltt_buffer_start), + sizeof(ltt_buffer_end), + sizeof(ltt_new_event), + sizeof(ltt_custom), + sizeof(ltt_change_mask), + 0 /* LTT_HEARTBEAT */ +}; + +/* Custom event description */ +struct custom_event_desc { + ltt_new_event event; + + pid_t owner_pid; + + struct custom_event_desc *next; + struct custom_event_desc *prev; +}; + +/* Custom event management */ +static int next_event_id = LTT_EV_MAX + 1; +static rwlock_t custom_list_lock = RW_LOCK_UNLOCKED; +static rwlock_t trace_handle_table_lock = RW_LOCK_UNLOCKED; +static struct custom_event_desc custom_events_head; +static struct custom_event_desc *custom_events = NULL; + +/* Handle management */ +struct trace_handle_struct{ + struct task_struct *owner; +}; +static struct trace_handle_struct trace_handle_table[LTT_MAX_HANDLES]; + +/* + * Helper functions + */ + +/** + * set_waiting_for_cpu_async: - Utility function for setting wait flags + * @cpu_id: which CPU to set flag on + * @bit: which bit to set + */ +static inline void set_waiting_for_cpu_async(unsigned int trace_handle, u8 cpu_id, int bit) +{ + atomic_set(&waiting_for_cpu_async(trace_handle, cpu_id), + atomic_read(&waiting_for_cpu_async(trace_handle, cpu_id)) | bit); +} + +/** + * clear_waiting_for_cpu_async: - Utility function for clearing wait flags + * @cpu_id: which CPU to clear flag on + * @bit: which bit to clear + */ +static inline void clear_waiting_for_cpu_async(unsigned int trace_handle, u8 cpu_id, int bit) +{ + atomic_set(&waiting_for_cpu_async(trace_handle, cpu_id), + atomic_read(&waiting_for_cpu_async(trace_handle, cpu_id)) & ~bit); +} + +/* + * Trace heartbeat + */ + +/** + * write_heartbeat_event: - Timer function generating hearbeat event. + * @data: unused + * + * Guarantees at least 1 event is logged before low word of TSC wraps. + */ +static void write_heartbeat_event(unsigned long data) +{ + unsigned long int flags; + int i, j; + + local_irq_save(flags); + for (i = 0; i < NR_TRACES; i++) { + if (current_traces[i].active && current_traces[i].using_tsc) { + for (j = 0; j < num_cpus; j++) + set_waiting_for_cpu_async(i, j, LTT_TRACE_HEARTBEAT); + } + } + local_irq_restore(flags); + + del_timer(&heartbeat_timer); + heartbeat_timer.expires = jiffies + 0xffffffffUL/loops_per_jiffy - 1; + add_timer(&heartbeat_timer); +} + +/** + * need_heartbeat: - If any active trace uses TSC timestamping, return 1 + * + * Returns the number of active traces using TSC timestamping + * + * Needed for starting/stopping the heartbeat timer depending on whether + * any trace needs it or not. + */ +int need_heartbeat(void) +{ + int i, retval = 0; + struct ltt_trace_struct *trace; + + for (i = 0; i < NR_TRACES; i++) { + trace = ¤t_traces[i]; + if(trace->active && trace->using_tsc) + retval++; + } + + return retval; +} + +/** + * init_heartbeat_timer: - Start timer generating hearbeat events. + */ +static void init_heartbeat_timer(void) +{ + if (loops_per_jiffy > 0) { + init_timer(&heartbeat_timer); + heartbeat_timer.function = write_heartbeat_event; + heartbeat_timer.expires = jiffies + + 0xffffffffUL/loops_per_jiffy - 1; + add_timer(&heartbeat_timer); + } else + printk(KERN_ALERT "LTT: No TSC for heartbeat timer - continuing without one \n"); +} + +/** + * delete_heartbeat_timer: - Stop timer generating hearbeat events. + */ +static void delete_heartbeat_timer(void) +{ + if (loops_per_jiffy > 0) + del_timer(&heartbeat_timer); +} + +/* + * Tasks and timers for trace finalization + */ + +/** + * all_channels_finalized: - Verify that all channels have been finalized. + * @trace_handle: the trace containing the channels to be tested + * + * Returns 1 if channels on all CPUs are complete, 0 otherwise. + */ +static int all_channels_finalized(unsigned int trace_handle) +{ + int i; + + for (i = 0; i < num_cpus; i++) + if (atomic_read(&waiting_for_cpu_async(trace_handle, i)) & LTT_FINALIZE_TRACE) + return 0; + + return 1; +} + +/** + * active_traces: - The number of currently active traces + * + * Returns the number of active traces + */ +static inline int active_traces(void) +{ + int i, nr_active = 0; + + for (i = 0; i < NR_TRACES; i++) + if (current_traces[i].active) + nr_active++; + + return nr_active; +} + +/** + * del_percpu_timers: - Delete all per_cpu timers. + */ +static inline void del_percpu_timers(void) +{ + int i; + + for (i = 0; i < num_cpus; i++) + del_timer_sync(&percpu_timer[i]); +} + +/** + * remove_readers_async: - Remove all map readers asynchronously. + * @private: the trace_handle containing the readers to be removed + */ +static void remove_readers_async(void *private) +{ + int i; + unsigned int trace_handle = (unsigned int)private; + + for (i = 0; i < num_cpus; i++) { + remove_map_reader(trace_channel_reader(trace_handle, i)); + trace_channel_reader(trace_handle, i) = NULL; + } +} + +/** + * remove_readers: - Remove all map readers. + * @trace_handle: the trace containing the readers to be removed + */ +static inline void remove_readers(unsigned int trace_handle) +{ + int i; + + for (i = 0; i < num_cpus; i++) { + remove_map_reader(trace_channel_reader(trace_handle, i)); + trace_channel_reader(trace_handle, i) = NULL; + } +} + +/** + * do_waiting_async_tasks: - perform asynchronous per-CPU tasks. + * @trace_handle: the trace handle + * @cpu_id: the CPU the tasks should be executed on + */ +static void do_waiting_async_tasks(unsigned int trace_handle, u8 cpu_id) +{ + unsigned long int flags; + int tasks; + struct ltt_trace_struct *trace; + + trace = ¤t_traces[trace_handle]; + + local_irq_save(flags); + tasks = atomic_read(&waiting_for_cpu_async(trace_handle, cpu_id)); + + if (tasks == 0) { + local_irq_restore(flags); + return; + } + + if (trace->using_tsc && trace->tracer_started && (tasks & LTT_TRACE_HEARTBEAT)) { + clear_waiting_for_cpu_async(trace_handle, cpu_id, LTT_TRACE_HEARTBEAT); + ltt_ev_heartbeat(); + } + + if (trace->tracer_stopping && (tasks & LTT_FINALIZE_TRACE)) { + clear_waiting_for_cpu_async(trace_handle, cpu_id, LTT_FINALIZE_TRACE); + if (relay_close(trace_channel_handle(trace_handle, cpu_id)) != 0) + printk(KERN_ALERT "LTT: Couldn't close trace channel %d\n", trace_channel_handle(trace_handle, cpu_id)); + + set_bit(cpu_id, &trace->buffer_switches_pending); + + if (all_channels_finalized(trace_handle)) { + PREPARE_WORK(&trace->work, remove_readers_async, (void *)trace_handle); + schedule_work(&trace->work); + + trace->tracer_stopping = 0; + } + } + + local_irq_restore(flags); +} + +/** + * check_waiting_async_tasks: - Timer function checking for async tasks. + * @data: unused + */ +static void check_waiting_async_tasks(unsigned long data) +{ + int i; + int cpu = smp_processor_id(); + + for (i = 0; i < NR_TRACES; i++) { + if (atomic_read(&waiting_for_cpu_async(i, cpu)) != 0) + do_waiting_async_tasks(i, cpu); + } + + del_timer(&percpu_timer[cpu]); + percpu_timer[cpu].expires = jiffies + LTT_PERCPU_TIMER_FREQ; + add_timer(&percpu_timer[cpu]); +} + +/** + * _init_percpu_timer: - Start timer checking for async tasks. + */ +void _init_percpu_timer(void * dummy) +{ + int cpu = smp_processor_id(); + + init_timer(&percpu_timer[cpu]); + percpu_timer[cpu].function = check_waiting_async_tasks; + percpu_timer[cpu].expires = jiffies + LTT_PERCPU_TIMER_FREQ; + add_timer(&percpu_timer[cpu]); +} + +static inline void init_percpu_timers(void) +{ + _init_percpu_timer(NULL); + + if (smp_call_function(_init_percpu_timer, NULL, 1, 1) != 0) + printk(KERN_ALERT "LTT: Couldn't initialize all per-CPU timers\n"); +} + +/* + * User-kernel interface for tracer + */ + +/** + * update_shared_buffer_control: - prepare for GET_BUFFER_CONTROL ioctl + * @trace: the trace instance + * @cpu_id: the CPU associated with the ioctl + */ +static inline void update_shared_buffer_control(struct ltt_trace_struct *trace, u8 cpu_id) +{ + struct rchan_info channel_info; + int i; + int channel_handle = trace_channel_handle(trace->trace_handle, cpu_id); + + if (relay_info(channel_handle, &channel_info) == -1) { + shared_buf_ctl.buffer_control_valid = 0; + return; + } + + shared_buf_ctl.cpu_id = cpu_id; + shared_buf_ctl.buffer_switches_pending = trace->buffer_switches_pending & ~(1UL << cpu_id); + shared_buf_ctl.buffer_control_valid = 1; + shared_buf_ctl.buf_size = channel_info.buf_size; + shared_buf_ctl.n_buffers = channel_info.n_bufs; + shared_buf_ctl.cur_idx = channel_info.cur_idx; + shared_buf_ctl.buffers_produced = channel_info.bufs_produced; + shared_buf_ctl.buffers_consumed = channel_info.bufs_consumed; + + if (channel_info.flags & RELAY_SCHEME_LOCKLESS) { + for (i = 0; i < channel_info.n_bufs; i++) { + shared_buf_ctl.buffer_complete[i] = + channel_info.buffer_complete[i]; + } + } +} + +/** + * ltt_flight_pause: - pause the flight recorder + * + * Allows for external control of flight recorder e.g. for crashdump + */ +void ltt_flight_pause(void) +{ + struct ltt_trace_struct *trace; + + trace = ¤t_traces[FLIGHT_HANDLE]; + if (!trace->active) + return; + + trace->paused = 1; +} + +/** + * ltt_flight_unpause: - unpause the flight recorder + * + * Allows for external control of flight recorder e.g. for crashdump + */ +void ltt_flight_unpause(void) +{ + struct ltt_trace_struct *trace; + + trace = ¤t_traces[FLIGHT_HANDLE]; + if (!trace->active) + return; + + trace->paused = 0; +} + +/** + * ltt_ioctl: - Tracing kernel-user control interface + * @rchan_id: rchan id ioctl occurred on + * @tracer_command: command given by the caller + * @command_arg: argument to the command + * + * Returns: + * >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 + * -EFAULT, unable to access user space memory + * -EACCES, invalid tracer handle + */ +static int ltt_ioctl(int rchan_id, + unsigned int tracer_command, + unsigned long arg) +{ + int retval; + int new_user_event_id; + unsigned long int flags; + u8 cpu_id; + u8 i; + u32 buffers_consumed; + ltt_custom user_event; + ltt_change_mask trace_mask; + ltt_new_event new_user_event; + struct ltt_buffers_committed buffers_committed; + struct ltt_trace_struct *trace = NULL; + struct ltt_tracer_status tracer_status; + unsigned int tracer_handle; + unsigned long command_arg; + + if (copy_from_user(&tracer_handle, (void *)arg, sizeof(unsigned int))) + return -EFAULT; + + if (copy_from_user(&command_arg, (void*)(arg + sizeof(tracer_handle)), sizeof(unsigned long))) + return -EFAULT; + + if (tracer_command == LTT_TRACER_ALLOC_HANDLE) + return ltt_alloc_trace_handle(tracer_handle); + + if (!ltt_valid_trace_handle(tracer_handle)) + return -EACCES; + + if (tracer_handle < NR_TRACES) + trace = ¤t_traces[tracer_handle]; + else if (tracer_handle >= NR_TRACES) { + if (current_traces[TRACE_HANDLE].active) + trace = ¤t_traces[TRACE_HANDLE]; + if (trace == NULL && tracer_command != LTT_TRACER_GET_STATUS) + return -EACCES; + } + + if ((tracer_handle < NR_TRACES) + && (trace->tracer_started == 1) + && (tracer_command != LTT_TRACER_STOP) + && (tracer_command != LTT_TRACER_PAUSE) + && (tracer_command != LTT_TRACER_UNPAUSE) + && (tracer_command != LTT_TRACER_DATA_COMITTED) + && (tracer_command != LTT_TRACER_GET_ARCH_INFO) + && (tracer_command != LTT_TRACER_GET_BUFFER_CONTROL) + && (tracer_command != LTT_TRACER_GET_START_INFO)) + return -EBUSY; + + if ((tracer_handle >= NR_TRACES) + && (tracer_command != LTT_TRACER_CREATE_USER_EVENT) + && (tracer_command != LTT_TRACER_DESTROY_USER_EVENT) + && (tracer_command != LTT_TRACER_TRACE_USER_EVENT) + && (tracer_command != LTT_TRACER_FREE_HANDLE) + && (tracer_command != LTT_TRACER_GET_STATUS) + && (tracer_command != LTT_TRACER_SET_EVENT_MASK) + && (tracer_command != LTT_TRACER_GET_EVENT_MASK)) + return -ENOSYS; + + switch (tracer_command) { + case LTT_TRACER_START: + if (trace->using_tsc && (need_heartbeat() == 1)) + init_heartbeat_timer(); + if (active_traces() == 1) + init_percpu_timers(); + + if (((use_syscall_eip_bounds == 1) + && (syscall_eip_depth_set == 1)) + || ((use_syscall_eip_bounds == 1) + && ((lower_eip_bound_set != 1) + || (upper_eip_bound_set != 1))) + || ((trace->tracing_pid == 1) + && (trace->tracing_pgrp == 1))) + return -EINVAL; + + if (ltt_set_trace_config(syscall_eip_depth_set, use_syscall_eip_bounds, syscall_eip_depth, + lower_eip_bound, upper_eip_bound) < 0) + return -EINVAL; + + if (trace->flight_recorder) + ltt_set_flight_recorder_config(trace); + + ltt_set_bit(LTT_EV_BUFFER_START, &trace->traced_events); + ltt_set_bit(LTT_EV_BUFFER_START, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_START, &trace->traced_events); + ltt_set_bit(LTT_EV_START, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_CHANGE_MASK, &trace->traced_events); + ltt_set_bit(LTT_EV_CHANGE_MASK, &trace->log_event_details_mask); + + syscall_entry_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_ENTRY); + syscall_exit_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_EXIT); + + trace->tracer_stopping = 0; + trace->tracer_started = 1; + + ltt_reregister_custom_events(); + break; + + case LTT_TRACER_STOP: + if (trace->flight_recorder) { + for (i = 0; i < num_cpus; i++) + tmp_rchan_handles[i] = trace_channel_handle(tracer_handle, i); + ltt_free_all_handles(NULL); + } else { + trace->tracer_stopping = 1; + trace->tracer_started = 0; + } + + syscall_entry_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_ENTRY); + syscall_exit_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_EXIT); + + if (trace->flight_recorder) { + for (i = 0; i < num_cpus; i++) { + if (relay_close(tmp_rchan_handles[i]) != 0) + printk(KERN_ALERT "LTT: Couldn't close trace channel %d\n", trace_channel_handle(tracer_handle, i)); + } + remove_readers(tracer_handle); + } else { + for (i = 0; i < num_cpus; i++) + set_waiting_for_cpu_async(tracer_handle, i, LTT_FINALIZE_TRACE); + } + break; + + case LTT_TRACER_PAUSE: + trace->paused = 1; + break; + + case LTT_TRACER_UNPAUSE: + trace->paused = 0; + break; + + case LTT_TRACER_CONFIG_DEFAULT: + ltt_set_default_config(trace); + break; + + case LTT_TRACER_CONFIG_MEMORY_BUFFERS: + if (trace->use_locking == 1) { + if (command_arg < LTT_TRACER_MIN_BUF_SIZE) + return -EINVAL; + } else { + if ((command_arg < LTT_TRACER_LOCKLESS_MIN_BUF_SIZE) || + (command_arg > LTT_TRACER_LOCKLESS_MAX_BUF_SIZE)) + return -EINVAL; + } + + return ltt_set_buffer_size(trace, command_arg, relayfs_path); + break; + + case LTT_TRACER_CONFIG_N_MEMORY_BUFFERS: + if (command_arg < LTT_TRACER_MIN_BUFFERS || + command_arg > LTT_TRACER_MAX_BUFFERS) + return -EINVAL; + + return ltt_set_n_buffers(trace, command_arg); + break; + + case LTT_TRACER_CONFIG_USE_LOCKING: + trace->use_locking = command_arg; + + if ((trace->use_locking == 0) && (have_cmpxchg() == 0)) + return -EINVAL; + break; + + case LTT_TRACER_CONFIG_EVENTS: + if (copy_from_user(&trace->traced_events, (void *) command_arg, sizeof(trace->traced_events))) + return -EFAULT; + break; + + case LTT_TRACER_CONFIG_TIMESTAMP: + trace->using_tsc = command_arg; + + if ((trace->using_tsc == 1) && (have_tsc() == 0)) { + trace->using_tsc = 0; + return -EINVAL; + } + + break; + + case LTT_TRACER_CONFIG_DETAILS: + if (copy_from_user(&trace->log_event_details_mask, (void *) command_arg, sizeof(trace->log_event_details_mask))) + return -EFAULT; + break; + + case LTT_TRACER_CONFIG_CPUID: + trace->log_cpuid = 0; /* disabled*/ + break; + + case LTT_TRACER_CONFIG_PID: + trace->tracing_pid = 1; + trace->traced_pid = command_arg; + break; + + case LTT_TRACER_CONFIG_PGRP: + trace->tracing_pgrp = 1; + trace->traced_pgrp = command_arg; + break; + + case LTT_TRACER_CONFIG_GID: + trace->tracing_gid = 1; + trace->traced_gid = command_arg; + break; + + case LTT_TRACER_CONFIG_UID: + trace->tracing_uid = 1; + trace->traced_uid = command_arg; + break; + + case LTT_TRACER_CONFIG_SYSCALL_EIP_DEPTH: + syscall_eip_depth_set = 1; + syscall_eip_depth = command_arg; + break; + + case LTT_TRACER_CONFIG_SYSCALL_EIP_LOWER: + use_syscall_eip_bounds = 1; + lower_eip_bound = (void *) command_arg; + lower_eip_bound_set = 1; + break; + + case LTT_TRACER_CONFIG_SYSCALL_EIP_UPPER: + use_syscall_eip_bounds = 1; + upper_eip_bound = (void *) command_arg; + upper_eip_bound_set = 1; + break; + + case LTT_TRACER_DATA_COMITTED: + if (copy_from_user(&buffers_committed, (void *)command_arg, + sizeof(buffers_committed))) + return -EFAULT; + + cpu_id = buffers_committed.cpu_id; + buffers_consumed = buffers_committed.buffers_consumed; + clear_bit(cpu_id, &trace->buffer_switches_pending); + + local_irq_save(flags); + relay_buffers_consumed(trace_channel_reader(tracer_handle, cpu_id), + buffers_consumed); + local_irq_restore(flags); + + break; + + case LTT_TRACER_GET_EVENTS_LOST: + return events_lost(tracer_handle, command_arg); + break; + + case LTT_TRACER_CREATE_USER_EVENT: + if (copy_from_user(&new_user_event, (void *) command_arg, sizeof(new_user_event))) + return -EFAULT; + + new_user_event_id = ltt_create_owned_event(new_user_event.type, + new_user_event.desc, + new_user_event.format_type, + new_user_event.form, + current->pid); + if (new_user_event_id >= 0) { + new_user_event.id = new_user_event_id; + if (copy_to_user((void *) command_arg, &new_user_event, sizeof(new_user_event))) { + ltt_destroy_event(new_user_event_id); + return -EFAULT; + } + } else + return new_user_event_id; + break; + + case LTT_TRACER_DESTROY_USER_EVENT: + ltt_destroy_event((int) command_arg); + break; + + case LTT_TRACER_TRACE_USER_EVENT: + if (copy_from_user(&user_event, (void *) command_arg, sizeof(user_event))) + return -EFAULT; + + if ((user_event_data == NULL) + && (user_event_data = vmalloc(LTT_CUSTOM_EV_MAX_SIZE)) < 0) + return -ENOMEM; + + if (copy_from_user(user_event_data, user_event.data, user_event.data_size)) + return -EFAULT; + + retval = ltt_log_raw_event(user_event.id, user_event.data_size, user_event_data); + + if (retval < 0) + return retval; + break; + + case LTT_TRACER_SET_EVENT_MASK: + if (copy_from_user(&(trace_mask.mask), (void *) command_arg, sizeof(trace_mask.mask))) + return -EFAULT; + + retval = _ltt_log_event(trace, LTT_EV_CHANGE_MASK, &trace_mask, smp_processor_id()); + + memcpy(&trace->traced_events, &(trace_mask.mask), sizeof(trace_mask.mask)); + + syscall_entry_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_ENTRY); + syscall_exit_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_EXIT); + + ltt_set_bit(LTT_EV_BUFFER_START, &trace->traced_events); + ltt_set_bit(LTT_EV_START, &trace->traced_events); + ltt_set_bit(LTT_EV_CHANGE_MASK, &trace->traced_events); + + return retval; + break; + + case LTT_TRACER_GET_EVENT_MASK: + if (copy_to_user((void *) command_arg, &trace->traced_events, sizeof(trace->traced_events))) + return -EFAULT; + break; + + case LTT_TRACER_GET_ARCH_INFO: + ltt_arch_info.n_cpus = num_cpus; + ltt_arch_info.page_shift = PAGE_SHIFT; + + if (copy_to_user((void *) command_arg, <t_arch_info, sizeof(ltt_arch_info))) + return -EFAULT; + break; + + case LTT_TRACER_GET_START_INFO: + if (trace->trace_start_data) { + if (copy_to_user((void *)command_arg, trace->trace_start_data, sizeof(ltt_trace_start))) + return -EFAULT; + } else + return -EINVAL; + break; + + case LTT_TRACER_GET_STATUS: + if (ltt_get_status(&tracer_status)) + return -EINVAL; + + if (copy_to_user((void *)command_arg, + &tracer_status, + sizeof(struct ltt_tracer_status))) + return -EFAULT; + break; + + case LTT_TRACER_GET_BUFFER_CONTROL: + if (copy_from_user(&shared_buf_ctl, (void *)command_arg, sizeof(shared_buf_ctl))) + return -EFAULT; + + if (shared_buf_ctl.cpu_id == -1) { + for (i = 0; i < num_cpus; i++) { + if (trace->buffer_switches_pending & (1UL << i)) { + update_shared_buffer_control(trace, i); + if (copy_to_user((void *)command_arg, &shared_buf_ctl, + sizeof(struct ltt_buf_control_info))) + return -EFAULT; + return 0; + } + } + } else { + update_shared_buffer_control(trace, (u8)shared_buf_ctl.cpu_id); + if (copy_to_user((void *)command_arg, &shared_buf_ctl, + sizeof(struct ltt_buf_control_info))) + return -EFAULT; + return 0; + } + + shared_buf_ctl.cpu_id = 0; + shared_buf_ctl.buffer_control_valid = 0; + + if (copy_to_user((void *) command_arg, &shared_buf_ctl, + sizeof(struct ltt_buf_control_info))) + return -EFAULT; + break; + + case LTT_TRACER_FREE_HANDLE: + return ltt_free_trace_handle(tracer_handle); + break; + + case LTT_TRACER_FREE_DAEMON_HANDLE: + return ltt_free_daemon_handle(trace); + break; + + case LTT_TRACER_FREE_ALL_HANDLES: + ltt_free_all_handles(current); + break; + + case LTT_TRACER_MAP_BUFFER: + return -EFAULT; + break; + + default: + return -ENOSYS; + break; + } + + return 0; +} + +/* + * Trace Handles + */ + +/** + * ltt_valid_trace_handle: - Validate tracer handle. + * @tracer_handle: handle to be validated + * + * Returns: + * 1, if handle is valid + * 0, if handle is invalid + */ +int ltt_valid_trace_handle(unsigned int tracer_handle) +{ + int retval = 0; + struct ltt_trace_struct *trace; + + if (tracer_handle < NR_TRACES) { + trace = ¤t_traces[tracer_handle]; + if (!trace->active) + retval = 0; + else if (!trace->flight_recorder) { + if (trace->daemon_task_struct == current) + retval = 1; + } else + retval = 1; + } else { + read_lock(&trace_handle_table_lock); + if (trace_handle_table[tracer_handle - NR_TRACES].owner == current) + retval = 1; + else + retval = 0; + read_unlock(&trace_handle_table_lock); + } + + return retval; +} + +/** + * ltt_alloc_trace_handle: - Allocate trace handle to caller. + * @tracer_handle: handle requested by process + * + * Returns: + * Handle ID, everything went OK + * -ENODEV, no more free handles. + * -EBUSY, daemon handle already in use. + */ +int ltt_alloc_trace_handle(unsigned int tracer_handle) +{ + int i; + int retval; + struct ltt_trace_struct *trace = NULL; + + if (tracer_handle < NR_TRACES) { + trace = ¤t_traces[tracer_handle]; + if (trace == NULL) + return -ENODEV; + if (trace->active) + return -EBUSY; + } + + if (tracer_handle >= NR_TRACES) { + write_lock(&trace_handle_table_lock); + for (i = 0; i < LTT_MAX_HANDLES; i++) + if (trace_handle_table[i].owner == NULL) { + trace_handle_table[i].owner = current; + break; + } + write_unlock(&trace_handle_table_lock); + if (i == LTT_MAX_HANDLES) + retval = -ENODEV; + else + retval = (i + NR_TRACES); + } else { + trace->active = trace; + trace->tracer_started = 0; + trace->tracer_stopping = 0; + if (tracer_handle == TRACE_HANDLE) { + trace->flight_recorder = 0; + trace->daemon_task_struct = current; + } else { + if ((trace->trace_start_data = (struct _ltt_trace_start *) kmalloc(sizeof(struct _ltt_trace_start), GFP_ATOMIC)) == NULL) + return -ENOMEM; + } + + trace->proc_dir_entry = create_handle_proc_dir(tracer_handle); + ltt_set_default_config(trace); + retval = trace->trace_handle = tracer_handle; + } + + return retval; +} + +/** + * ltt_free_trace_handle: - Free a single handle. + * tracer_handle: handle to be freed. + * + * Returns: + * 0, everything went OK + * -ENODEV, no such handle. + * -EACCES, handle doesn't belong to caller. + */ +int ltt_free_trace_handle(unsigned int tracer_handle) +{ + int retval; + + if ((tracer_handle < NR_TRACES) || (tracer_handle >= LTT_MAX_HANDLES)) + return -ENODEV; + + write_lock(&trace_handle_table_lock); + + if (trace_handle_table[tracer_handle - NR_TRACES].owner == current) { + trace_handle_table[tracer_handle - NR_TRACES].owner = NULL; + retval = 0; + } else + retval = -EACCES; + + write_unlock(&trace_handle_table_lock); + + return retval; +} + +/** + * ltt_free_daemon_handle: - Free the daemon's handle. + * @trace: the trace instance + * + * Returns: + * 0, everything went OK + * -EACCES, handle doesn't belong to caller. + * -EBUSY, there are still event writes in progress so the buffer can't + * be released. + */ +int ltt_free_daemon_handle(struct ltt_trace_struct *trace) +{ + int i; + + if (!trace->flight_recorder) { + if (trace->daemon_task_struct != current) + return -EACCES; + + for (i = 0; i < num_cpus; i++) { + if (events_lost(trace->trace_handle, i) > 0) + printk(KERN_ALERT "LTT: Lost %d events on cpu %d\n", + events_lost(trace->trace_handle, i), i); + } + trace->daemon_task_struct = NULL; + } + + trace->active = NULL; + + if (!active_traces()) + del_percpu_timers(); + + if(trace->using_tsc && !need_heartbeat()) + delete_heartbeat_timer(); + + for (i = 0; i < num_cpus; i++) { + if (trace_channel_handle(trace->trace_handle, i) != -1) { + trace_channel_handle(trace->trace_handle, i) = -1; + trace_channel_reader(trace->trace_handle, i) = NULL; + } + } + + remove_handle_proc_dir(trace->proc_dir_entry, 0); + + trace->use_locking = 1; + ltt_set_default_config(trace); + trace->tracer_started = 0; + trace->tracer_stopping = 0; + if (trace->trace_start_data) + kfree(trace->trace_start_data); + + return 0; +} + +/** + * ltt_free_all_handles: - Free all handles taken. + * @task_ptr: pointer to exiting task. + * + * Free all handles taken against a given channel. If task_ptr is NULL, + * it means there is no daemon, i.e. free all handles taken agains the + * flight recorder channel, otherwise task_ptr refers to a trace daemon. + */ +void ltt_free_all_handles(struct task_struct* task_ptr) +{ + int i; + struct ltt_trace_struct *trace; + + if (task_ptr == NULL) { + if (current_traces[FLIGHT_HANDLE].active) { + ltt_free_daemon_handle(¤t_traces[FLIGHT_HANDLE]); + return; + } + } else { + trace = ¤t_traces[TRACE_HANDLE]; + if (trace->active && trace->daemon_task_struct == task_ptr) + ltt_free_daemon_handle(trace); + } + + write_lock(&trace_handle_table_lock); + for (i = 0; i < LTT_MAX_HANDLES; i++) + if (trace_handle_table[i].owner == current) + trace_handle_table[i].owner = NULL; + write_unlock(&trace_handle_table_lock); +} + +/* + * Tracer Configuration + */ + +/** + * init_trace: - Initialize a trace/flight recorder instance + * @trace_struct: trace/flight recorder struct + * + * Initialize a trace instance to default values. + */ +static void init_trace(struct ltt_trace_struct *trace) +{ + trace->trace_handle = 0; + + trace->active = NULL; + trace->paused = 0; + trace->flight_recorder = 1; + trace->daemon_task_struct = NULL; + trace->trace_start_data = NULL; + + trace->tracer_started = 0; + trace->tracer_stopping = 0; + trace->proc_dir_entry = NULL; + trace->traced_events = 0; + trace->log_event_details_mask = 0; + trace->log_cpuid = 0; + trace->tracing_pid = 0; + trace->tracing_pgrp = 0; + trace->tracing_gid = 0; + trace->tracing_uid = 0; + trace->traced_pid = 0; + trace->traced_pgrp = 0; + trace->traced_gid = 0; + trace->traced_uid = 0; + trace->use_locking = 1; + trace->n_buffers = 0; + trace->buf_size = 0; + trace->using_tsc = 0; + + trace->buffer_switches_pending = 0; + INIT_WORK(&trace->work, NULL, NULL); +} + +/** + * ltt_syscall_active: - If any active trace is logging syscalls, return 1 + * @syscall_type: either SYSCALL_ENTRY or SYSCALL_EXIT + * + * Returns 1 if any channel is tracing syscalls, 0 otherwise + * + * Needed for setting/clearing the global syscall...active variables + * in order to reflect the needs of all traces. + */ +int ltt_syscall_active(int syscall_type) +{ + int i, retval = 0; + struct ltt_trace_struct *trace; + + for (i = 0; i < NR_TRACES; i++) { + trace = ¤t_traces[i]; + if (!trace->active) + continue; + if(ltt_test_bit(syscall_type, &trace->traced_events)) + retval = 1; + } + + return retval; +} + +/** + * init_channel_data: - Init channel-associated data for new tracing run. + * @trace: the trace to be initialized + */ +static void init_channel_data(struct ltt_trace_struct *trace) +{ + unsigned i; + + trace->buffer_switches_pending = 0; + + for (i = 0; i < num_cpus; i++) { + trace_channel_handle(trace->trace_handle, i) = -1; + trace_channel_reader(trace->trace_handle, i) = NULL; + atomic_set(&waiting_for_cpu_async(trace->trace_handle, i), LTT_NOTHING_TO_DO); + events_lost(trace->trace_handle, i) = 0; + } +} + +/** + * ltt_set_n_buffers: - Sets the number of buffers. + * @trace: the trace instance + * @no_buffers: number of buffers + * + * For lockless only, must be a power of 2. + * + * Returns: + * + * 0, Size setting went OK + * -EINVAL, not a power of 2 + */ +int ltt_set_n_buffers(struct ltt_trace_struct *trace, int no_buffers) +{ + if (hweight32(no_buffers) != 1) + return -EINVAL; + + trace->n_buffers = no_buffers; + + return 0; +} + +/** + * ltt_set_buffer_size: - Sets size of and creates buffers. + * @buf_size: Size of sub-buffers + * @dirname: name of the relayfs directory to contain trace files + * + * Note: dirname should be well-formed before it gets here e.g. + * trailing slashes should be removed. + * + * Returns: + * 0, Size setting went OK + * -ENOMEM, unable to get a hold of memory for tracer + * -EINVAL, tracer not properly configured + */ +int ltt_set_buffer_size(struct ltt_trace_struct *trace, int buffer_size, char * dirname) +{ + int i; + u32 flags; + + if (trace->flight_recorder) + flags = RELAY_DELIVERY_BULK | RELAY_USAGE_SMP | RELAY_MODE_CONTINUOUS; + else + flags = RELAY_DELIVERY_BULK | RELAY_USAGE_SMP | RELAY_MODE_NO_OVERWRITE; + + if ((dirname == NULL) || (strlen(dirname) == 0)) + return -EINVAL; + + if (trace->using_tsc) + flags |= RELAY_TIMESTAMP_TSC; + else + flags |= RELAY_TIMESTAMP_GETTIMEOFDAY; + + if (trace->use_locking) + flags |= RELAY_SCHEME_LOCKING; + else + flags |= RELAY_SCHEME_LOCKLESS; + + num_cpus = num_online_cpus(); + + init_channel_data(trace); + + trace->buf_size = buffer_size; + + for (i = 0; i < num_cpus; i++) { + sprintf(relay_file_name, "%s/cpu%d", dirname, i); + trace_channel_handle(trace->trace_handle, i) = + relay_open(relay_file_name, buffer_size, trace->n_buffers, + flags, <t_callbacks, start_reserve, end_reserve, + trace_start_reserve, 0, 0, 0, NULL, 0); + if (trace_channel_handle(trace->trace_handle, i) < 0) + return -ENOMEM; + } + + return 0; +} + +/** + * ltt_set_default_config: - Sets the tracer in its default config + * + * Returns: + * 0, everything went OK + * -ENOMEM, unable to get a hold of memory for tracer + */ +int ltt_set_default_config(struct ltt_trace_struct *trace) +{ + int i; + int retval = 0; + + trace->traced_events = 0; + + for (i = 0; i <= LTT_EV_MAX; i++) { + ltt_set_bit(i, &trace->traced_events); + ltt_set_bit(i, &trace->log_event_details_mask); + } + + syscall_entry_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_ENTRY); + syscall_exit_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_EXIT); + + trace->log_cpuid = 0; + trace->tracing_pid = 0; + trace->tracing_pgrp = 0; + trace->tracing_gid = 0; + trace->tracing_uid = 0; + trace->using_tsc = 0; + + syscall_eip_depth_set = 0; + use_syscall_eip_bounds = 0; + lower_eip_bound_set = 0; + upper_eip_bound_set = 0; + + ltt_set_trace_config(syscall_eip_depth_set, use_syscall_eip_bounds, 0, 0, 0); + + return retval; +} + +/** + * ltt_set_trace_config: - Set the tracing configuration + * @do_syscall_depth: Use depth to fetch eip + * @do_syscall_bounds: Use bounds to fetch eip + * @eip_depth: Detph to fetch eip + * @eip_lower_bound: Lower bound eip address + * @eip_upper_bound: Upper bound eip address + * + * Returns: + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer + * -ENXIO, wrong tracer + * -EINVAL, invalid configuration + */ +int ltt_set_trace_config(int do_syscall_depth, + int do_syscall_bounds, + int eip_depth, + void *eip_lower_bound, + void *eip_upper_bound) +{ + if ((do_syscall_depth && do_syscall_bounds) + || (eip_lower_bound > eip_upper_bound) + || (eip_depth < 0)) + return -EINVAL; + + fetch_syscall_eip_use_depth = do_syscall_depth; + fetch_syscall_eip_use_bounds = do_syscall_bounds; + + syscall_eip_depth = eip_depth; + syscall_lower_eip_bound = eip_lower_bound; + syscall_upper_eip_bound = eip_upper_bound; + + return 0; +} + +/** + * ltt_get_trace_config: - Get the tracing configuration + * @do_syscall_depth: Use depth to fetch eip + * @do_syscall_bounds: Use bounds to fetch eip + * @eip_depth: Detph to fetch eip + * @eip_lower_bound: Lower bound eip address + * @eip_upper_bound: Upper bound eip address + * + * Returns: + * 0, all is OK + * -ENOMEDIUM, there isn't a registered tracer + */ +int ltt_get_trace_config(int *do_syscall_depth, + int *do_syscall_bounds, + int *eip_depth, + void **eip_lower_bound, + void **eip_upper_bound) +{ + *do_syscall_depth = fetch_syscall_eip_use_depth; + *do_syscall_bounds = fetch_syscall_eip_use_bounds; + *eip_depth = syscall_eip_depth; + *eip_lower_bound = syscall_lower_eip_bound; + *eip_upper_bound = syscall_upper_eip_bound; + + return 0; +} + +/** + * ltt_set_flight_recorder_config: - set flight recorder defaults + * @trace: the trace struct + */ +void ltt_set_flight_recorder_config(struct ltt_trace_struct *trace) +{ + trace->traced_events = 0; + trace->log_event_details_mask = 0; + + ltt_set_bit(LTT_EV_BUFFER_START, &trace->traced_events); + ltt_set_bit(LTT_EV_BUFFER_START, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_START, &trace->traced_events); + ltt_set_bit(LTT_EV_START, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_CHANGE_MASK, &trace->traced_events); + ltt_set_bit(LTT_EV_CHANGE_MASK, &trace->log_event_details_mask); + + ltt_set_bit(LTT_EV_SYSCALL_ENTRY, &trace->traced_events); + ltt_set_bit(LTT_EV_SYSCALL_ENTRY, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_SYSCALL_EXIT, &trace->traced_events); + ltt_set_bit(LTT_EV_SYSCALL_EXIT, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_TRAP_ENTRY, &trace->traced_events); + ltt_set_bit(LTT_EV_TRAP_ENTRY, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_TRAP_EXIT, &trace->traced_events); + ltt_set_bit(LTT_EV_TRAP_EXIT, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_IRQ_ENTRY, &trace->traced_events); + ltt_set_bit(LTT_EV_IRQ_ENTRY, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_IRQ_EXIT, &trace->traced_events); + ltt_set_bit(LTT_EV_IRQ_EXIT, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_SCHEDCHANGE, &trace->traced_events); + ltt_set_bit(LTT_EV_SCHEDCHANGE, &trace->log_event_details_mask); + + ltt_set_bit(LTT_EV_KERNEL_TIMER, &trace->traced_events); + ltt_set_bit(LTT_EV_KERNEL_TIMER, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_SOFT_IRQ, &trace->traced_events); + ltt_set_bit(LTT_EV_SOFT_IRQ, &trace->log_event_details_mask); + ltt_set_bit(LTT_EV_PROCESS, &trace->traced_events); + ltt_set_bit(LTT_EV_PROCESS, &trace->log_event_details_mask); +} + +/** + * ltt_get_status: - fill in a status struct covering all traces + * @tracer_status: the tracer_status struct + */ +int ltt_get_status(struct ltt_tracer_status *tracer_status) +{ + int i, j, rchan_handle, retval = 0; + struct ltt_trace_struct *trace; + struct ltt_trace_info *info; + struct rchan_info rchan_info; + + tracer_status->num_cpus = num_cpus; + + for (i = 0; i < NR_TRACES; i++) { + trace = ¤t_traces[i]; + info = &tracer_status->traces[i]; + info->active = trace->active && trace->tracer_started ? 1 : 0; + if (!info->active) + continue; + info->trace_handle = trace->trace_handle; + info->paused = trace->paused; + info->flight_recorder = trace->flight_recorder; + info->use_locking = trace->use_locking; + info->using_tsc = trace->using_tsc; + info->n_buffers = trace->n_buffers; + info->buf_size = trace->buf_size; + info->traced_events = trace->traced_events; + info->log_event_details_mask = trace->log_event_details_mask; + for (j = 0; j < num_cpus; j++) { + rchan_handle = trace_channel_handle(trace->trace_handle, j); + retval = relay_info(rchan_handle, &rchan_info); + if (retval) + return retval; + info->buffers_produced[j] = rchan_info.bufs_produced; + } + } + + return retval; +} + +/* + * Custom Events + */ + +/** + * init_custom_events: - Initialize custom events + */ +static inline void init_custom_events(void) +{ + custom_events = &custom_events_head; + custom_events->next = custom_events; + custom_events->prev = custom_events; +} + +/** + * _ltt_create_event: - Create a new traceable event type + * @event_type: string describing event type + * @event_desc: string used for standard formatting + * @format_type: type of formatting used to log event data + * @format_data: data specific to format + * @owner_pid: PID of event's owner (0 if none) + * + * Returns: + * New Event ID if all is OK + * -ENOMEM, Unable to allocate new event + */ +int _ltt_create_event(char *event_type, + char *event_desc, + int format_type, + char *format_data, + pid_t owner_pid) +{ + ltt_new_event *new_event; + struct custom_event_desc *new_event_desc; + + if ((new_event_desc = (struct custom_event_desc *) kmalloc(sizeof(struct custom_event_desc), GFP_ATOMIC)) == NULL) + return -ENOMEM; + + new_event = &(new_event_desc->event); + new_event->type[0] = '\0'; + new_event->desc[0] = '\0'; + new_event->form[0] = '\0'; + + if (event_type != NULL) + strncpy(new_event->type, event_type, LTT_CUSTOM_EV_TYPE_STR_LEN); + if (event_desc != NULL) + strncpy(new_event->desc, event_desc, LTT_CUSTOM_EV_DESC_STR_LEN); + if (format_data != NULL) + strncpy(new_event->form, format_data, LTT_CUSTOM_EV_FORM_STR_LEN); + + new_event->type[LTT_CUSTOM_EV_TYPE_STR_LEN - 1] = '\0'; + new_event->desc[LTT_CUSTOM_EV_DESC_STR_LEN - 1] = '\0'; + new_event->form[LTT_CUSTOM_EV_FORM_STR_LEN - 1] = '\0'; + + new_event->format_type = format_type; + new_event->id = next_event_id; + + next_event_id++; + + new_event_desc->owner_pid = owner_pid; + + write_lock(&custom_list_lock); + + if (custom_events == NULL) + init_custom_events(); + + new_event_desc->next = custom_events; + new_event_desc->prev = custom_events->prev; + custom_events->prev->next = new_event_desc; + custom_events->prev = new_event_desc; + write_unlock(&custom_list_lock); + + ltt_log_event(LTT_EV_NEW_EVENT, &(new_event_desc->event)); + + return new_event->id; +} + +int ltt_create_event(char *event_type, + char *event_desc, + int format_type, + char *format_data) +{ + return _ltt_create_event(event_type, event_desc, format_type, format_data, 0); +} + +int ltt_create_owned_event(char *event_type, + char *event_desc, + int format_type, + char *format_data, + pid_t owner_pid) +{ + return _ltt_create_event(event_type, event_desc, format_type, format_data, owner_pid); +} + +/** + * ltt_destroy_event: - Destroy a created event type + * @event_id, the Id returned by ltt_create_event() + */ +void ltt_destroy_event(int event_id) +{ + struct custom_event_desc *event_desc; + + write_lock(&custom_list_lock); + + if (custom_events == NULL) + init_custom_events(); + + for (event_desc = custom_events->next; + event_desc != custom_events; + event_desc = event_desc->next) + if (event_desc->event.id == event_id) + break; + + if (event_desc != custom_events) { + event_desc->next->prev = event_desc->prev; + event_desc->prev->next = event_desc->next; + kfree(event_desc); + } + + write_unlock(&custom_list_lock); +} + +/** + * ltt_destroy_owners_events: Destroy an owner's events + * @owner_pid: the PID of the owner who's events are to be deleted. + */ +void ltt_destroy_owners_events(pid_t owner_pid) +{ + struct custom_event_desc *temp_event; + struct custom_event_desc *event_desc; + + write_lock(&custom_list_lock); + + if (custom_events == NULL) + init_custom_events(); + + event_desc = custom_events->next; + + while (event_desc != custom_events) { + temp_event = event_desc->next; + if (event_desc->owner_pid == owner_pid) { + event_desc->next->prev = event_desc->prev; + event_desc->prev->next = event_desc->next; + kfree(event_desc); + } + event_desc = temp_event; + } + + write_unlock(&custom_list_lock); +} + +/** + * ltt_reregister_custom_events: - Relogs event creations. + */ +void ltt_reregister_custom_events(void) +{ + struct custom_event_desc *event_desc; + + read_lock(&custom_list_lock); + + if (custom_events == NULL) + init_custom_events(); + + for (event_desc = custom_events->next; + event_desc != custom_events; + event_desc = event_desc->next) + ltt_log_event(LTT_EV_NEW_EVENT, &(event_desc->event)); + + read_unlock(&custom_list_lock); +} + +/* + * Event logging primitives + */ + +/** + * _ltt_log_event: - Tracing function per se. + * @trace: the trace instance + * @event_id: ID of event as defined in linux/ltt.h + * @event_struct: struct describing the event + * @cpu_id: the CPU associated with the event + * + * Returns: + * 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. + */ +int _ltt_log_event(struct ltt_trace_struct *trace, + u8 event_id, + void *event_struct, + u8 cpu_id) +{ + int var_data_len = 0; + void *var_data_beg = NULL; + uint16_t data_size; + struct task_struct *incoming_process = NULL; + unsigned long flags; + char * reserved; + int bytes_written = 0; + int reserve_code, interrupting; + struct timeval time_stamp; + u32 time_delta; + int channel_handle; + struct rchan *rchan; + unsigned int tracer_handle; + + if (!trace) + return -ENOMEDIUM; + + if (trace->paused) + return -EBUSY; + + tracer_handle = trace->trace_handle; + + if (!trace->flight_recorder && (trace->daemon_task_struct == NULL)) + return -ENODEV; + + channel_handle = trace_channel_handle(tracer_handle, cpu_id); + + if ((trace->tracer_started == 1) || (event_id == LTT_EV_START) || (event_id == LTT_EV_BUFFER_START)) + goto trace_event; + + return -EBUSY; + +trace_event: + if (!ltt_test_bit(event_id, &trace->traced_events)) + return 0; + + if ((event_id != LTT_EV_START) && (event_id != LTT_EV_BUFFER_START)) { + if (event_id == LTT_EV_SCHEDCHANGE) + incoming_process = (struct task_struct *) (((ltt_schedchange *) event_struct)->in); + if ((trace->tracing_pid == 1) && (current->pid != trace->traced_pid)) { + if (incoming_process == NULL) + return 0; + else if (incoming_process->pid != trace->traced_pid) + return 0; + } + if ((trace->tracing_pgrp == 1) && (process_group(current) != trace->traced_pgrp)) { + if (incoming_process == NULL) + return 0; + else if (process_group(incoming_process) != trace->traced_pgrp) + return 0; + } + if ((trace->tracing_gid == 1) && (current->egid != trace->traced_gid)) { + if (incoming_process == NULL) + return 0; + else if (incoming_process->egid != trace->traced_gid) + return 0; + } + if ((trace->tracing_uid == 1) && (current->euid != trace->traced_uid)) { + if (incoming_process == NULL) + return 0; + else if (incoming_process->euid != trace->traced_uid) + return 0; + } + if (event_id == LTT_EV_SCHEDCHANGE) + (((ltt_schedchange *) event_struct)->in) = incoming_process->pid; + } + + data_size = sizeof(event_id) + sizeof(time_delta) + sizeof(data_size); + + if (ltt_test_bit(event_id, &trace->log_event_details_mask)) { + data_size += event_struct_size[event_id]; + switch (event_id) { + case LTT_EV_FILE_SYSTEM: + if ((((ltt_file_system *) event_struct)->event_sub_id == LTT_EV_FILE_SYSTEM_EXEC) + || (((ltt_file_system *) event_struct)->event_sub_id == LTT_EV_FILE_SYSTEM_OPEN)) { + var_data_beg = ((ltt_file_system *) event_struct)->file_name; + var_data_len = ((ltt_file_system *) event_struct)->event_data2 + 1; + data_size += (uint16_t) var_data_len; + } + break; + case LTT_EV_CUSTOM: + var_data_beg = ((ltt_custom *) event_struct)->data; + var_data_len = ((ltt_custom *) event_struct)->data_size; + data_size += (uint16_t) var_data_len; + break; + } + } + + if ((trace->log_cpuid == 1) && (event_id != LTT_EV_START) && (event_id != LTT_EV_BUFFER_START)) + data_size += sizeof(cpu_id); + + rchan = rchan_get(channel_handle); + if (rchan == NULL) + return -ENODEV; + + relay_lock_channel(rchan, flags); /* nop for lockless */ + reserved = relay_reserve(rchan, data_size, &time_stamp, &time_delta, &reserve_code, &interrupting); + + if (reserve_code & RELAY_WRITE_DISCARD) { + events_lost(trace->trace_handle, cpu_id)++; + bytes_written = 0; + goto check_buffer_switch; + } + + if ((trace->log_cpuid == 1) && (event_id != LTT_EV_START) + && (event_id != LTT_EV_BUFFER_START)) + relay_write_direct(reserved, + &cpu_id, + sizeof(cpu_id)); + + relay_write_direct(reserved, + &event_id, + sizeof(event_id)); + + relay_write_direct(reserved, + &time_delta, + sizeof(time_delta)); + + if (ltt_test_bit(event_id, &trace->log_event_details_mask)) { + relay_write_direct(reserved, + event_struct, + event_struct_size[event_id]); + if (var_data_len) + relay_write_direct(reserved, + var_data_beg, + var_data_len); + } + + relay_write_direct(reserved, + &data_size, + sizeof(data_size)); + + bytes_written = data_size; + +check_buffer_switch: + if ((event_id == LTT_EV_SCHEDCHANGE) && (tracer_handle == TRACE_HANDLE) && current_traces[FLIGHT_HANDLE].active) + (((ltt_schedchange *) event_struct)->in) = (u32)incoming_process; + + /* We need to commit even if we didn't write anything because + that's how the deliver callback is invoked. */ + relay_commit(rchan, reserved, bytes_written, reserve_code, interrupting); + + relay_unlock_channel(rchan, flags); + rchan_put(rchan); + + return 0; +} + +/** + * ltt_log_event: - Trace an event + * @event_id, the event's ID (check out ltt.h) + * @event_struct, the structure describing the event + * + * Returns: + * Trace fct return code if OK. + * -ENOMEDIUM, there is no registered tracer + * -ENOMEM, couldn't access ltt_info + */ +int ltt_log_event(u8 event_id, + void *event_struct) +{ + int i; + static int err[NR_TRACES]; + struct ltt_trace_struct *trace; + u32 cpu = smp_processor_id(); + + for (i = 0; i < NR_TRACES; i++) { + trace = current_traces[i].active; + err[i] = _ltt_log_event(trace, event_id, event_struct, cpu); + } + + return err[0] == -ENOMEDIUM ? err[1] : err[0]; +} + +/** + * ltt_log_std_formatted_event: - Trace a formatted event + * @event_id: the event Id provided upon creation + * @...: printf-like data that will be used to fill the event string. + * + * Returns: + * Trace fct return code if OK. + * -ENOMEDIUM, there is no registered tracer or event doesn't exist. + */ +int ltt_log_std_formatted_event(int event_id,...) +{ + int string_size; + char final_string[LTT_CUSTOM_EV_FINAL_STR_LEN]; + va_list vararg_list; + ltt_custom custom_event; + struct custom_event_desc *event_desc; + + read_lock(&custom_list_lock); + + if (custom_events == NULL) + init_custom_events(); + + for (event_desc = custom_events->next; + event_desc != custom_events; + event_desc = event_desc->next) + if (event_desc->event.id == event_id) + break; + + if (event_desc == custom_events) { + read_unlock(&custom_list_lock); + return -ENOMEDIUM; + } + + custom_event.id = event_id; + + va_start(vararg_list, event_id); + string_size = vsprintf(final_string, event_desc->event.desc, vararg_list); + read_unlock(&custom_list_lock); + va_end(vararg_list); + + custom_event.data_size = (u32) (string_size + 1); + custom_event.data = final_string; + + return ltt_log_event(LTT_EV_CUSTOM, &custom_event); +} + +/** + * ltt_log_raw_event: - Trace a raw event + * @event_id, the event Id provided upon creation + * @event_size, the size of the data provided + * @event_data, data buffer describing event + * + * Returns: + * Trace fct return code if OK. + * -ENOMEDIUM, there is no registered tracer or event doesn't exist. + */ +int ltt_log_raw_event(int event_id, int event_size, void *event_data) +{ + ltt_custom custom_event; + struct custom_event_desc *event_desc; + + read_lock(&custom_list_lock); + + if (custom_events == NULL) + init_custom_events(); + + for (event_desc = custom_events->next; + event_desc != custom_events; + event_desc = event_desc->next) + if (event_desc->event.id == event_id) + break; + + read_unlock(&custom_list_lock); + + if (event_desc == custom_events) + return -ENOMEDIUM; + + custom_event.id = event_id; + + if (event_size <= LTT_CUSTOM_EV_MAX_SIZE) + custom_event.data_size = (u32) event_size; + else + custom_event.data_size = (u32) LTT_CUSTOM_EV_MAX_SIZE; + + custom_event.data = event_data; + + return ltt_log_event(LTT_EV_CUSTOM, &custom_event); +} + +/* + * Relayfs callback implementations. + */ + +/** + * _ltt_channel_cpuid: - Get CPU id given channel handle, for given trace. + * @tracer_handle: trace handle. + * @channel_handle: relay channel handle. + * + * Returns: + * + * CPU id + * -1, channel_handle, thus CPU id, not found + */ +static int _ltt_channel_cpuid(int tracer_handle, int channel_handle) +{ + int i; + + for (i = 0; i < num_cpus; i++) + if (trace_channel_handle(tracer_handle, i) == channel_handle) + return i; + + return -1; +} + +/** + * ltt_channel_cpuid: - Get CPU id given channel handle. + * @channel_handle: relay channel handle. + * + * Returns: + * + * CPU id + * -1, channel_handle, thus CPU id, not found + */ +static int ltt_channel_cpuid(int channel_handle) +{ + int i, cpuid; + + for (i = 0; i < NR_TRACES; i++) { + cpuid = _ltt_channel_cpuid(i, channel_handle); + if (cpuid != -1) + return cpuid; + } + + return -1; +} + +/** + * ltt_channel_trace: - Get trace struct given channel handle. + * @channel_handle: relay channel handle. + * + * Returns: + * + * trace struct * + * NULL, channel_handle, thus trace_struct *, not found + */ +static struct ltt_trace_struct *ltt_channel_trace(int channel_handle) +{ + int i; + + for (i = 0; i < NR_TRACES; i++) { + if (_ltt_channel_cpuid(i, channel_handle) != -1) + return ¤t_traces[i]; + } + + return NULL; +} + +/** + * ltt_channel_trace_handle: - Get trace handle given channel handle. + * @channel_handle: relay channel handle. + * + * Returns: + * + * trace handle + * -1, channel_handle, thus trace handle, not found + */ +static int ltt_channel_trace_handle(int channel_handle) +{ + unsigned int i; + + for (i = 0; i < NR_TRACES; i++) + if (_ltt_channel_cpuid(i, channel_handle) != -1) + return i; + + return -1; +} + +/** + * write_start_event: - Initialize a trace session for a given CPU. + * @cpu_id: the CPU id to initialize a trace for + */ +static inline int write_start_event(struct ltt_trace_struct *trace, + int channel, + char * current_write_pos, + u32 start_tsc, + int using_tsc) +{ + struct rchan_info channel_info; + u32 time_delta; + ltt_trace_start start_event; + u8 event_id; + uint16_t data_size; + + relay_info(channel, &channel_info); + + start_event.magic_number = LTT_TRACER_MAGIC_NUMBER; + start_event.arch_type = LTT_ARCH_TYPE; + start_event.arch_variant = LTT_ARCH_VARIANT; + start_event.system_type = LTT_SYS_TYPE_VANILLA_LINUX; + start_event.major_version = LTT_TRACER_VERSION_MAJOR; + start_event.minor_version = LTT_TRACER_VERSION_MINOR; + start_event.buffer_size = channel_info.buf_size; + start_event.event_mask = trace->traced_events; + start_event.details_mask = trace->log_event_details_mask; + start_event.log_cpuid = trace->log_cpuid; + start_event.use_tsc = trace->using_tsc; + start_event.flight_recorder = trace->flight_recorder; + + event_id = LTT_EV_START; + relay_write_direct(current_write_pos, &event_id, sizeof(event_id)); + + time_delta = switch_time_delta(start_tsc, using_tsc); + relay_write_direct(current_write_pos, &time_delta, sizeof(time_delta)); + + relay_write_direct(current_write_pos, &start_event, sizeof(ltt_trace_start)); + + data_size = sizeof(event_id) + sizeof(time_delta) + sizeof(ltt_trace_start) + sizeof(data_size); + + relay_write_direct(current_write_pos, &data_size, sizeof(data_size)); + + if (trace->trace_start_data) + memcpy(trace->trace_start_data, &start_event, sizeof(start_event)); + + return (int)data_size; +} + +/** + * buffer_start_callback: - Write start-buffer event to start of buffer. + * @channel_handle: the channel id + * @current_write_pos: position in sub-buffer client should write to + * @buffer_id: the id of the new sub-buffer + * @start_time: the timestamp associated with the start of sub-buffer + * @start_tsc: the TSC associated with the timestamp, if using_tsc + * @using_tsc: boolean, indicates whether start_tsc is valid + * + * This is the relayfs buffer_start() callback implementation for + * the tracer. We write the start event directly to the address + * contained in the current_write_pos param. If this is the first + * sub-buffer, we also write the start event. Of course we reserved + * the number of bytes we're writing when we opened the channel, which + * is the number we return. + */ +static int buffer_start_callback(int channel_handle, + char * current_write_pos, + u32 buffer_id, + struct timeval start_time, + u32 start_tsc, + int using_tsc) +{ + ltt_buffer_start start_buffer_event; + u8 event_id; + u32 time_delta; + uint16_t data_size; + struct ltt_trace_struct *trace = ltt_channel_trace(channel_handle); + + if (!trace) + return 0; + + start_buffer_event.id = buffer_id; + start_buffer_event.time = start_time; + start_buffer_event.tsc = start_tsc; + + event_id = LTT_EV_BUFFER_START; + relay_write_direct(current_write_pos, &event_id, sizeof(event_id)); + + time_delta = switch_time_delta(start_tsc, using_tsc); + relay_write_direct(current_write_pos, &time_delta, sizeof(time_delta)); + + relay_write_direct(current_write_pos, &start_buffer_event, sizeof(start_buffer_event)); + + data_size = sizeof(event_id) + sizeof(time_delta) + sizeof(start_buffer_event) + sizeof(data_size); + + relay_write_direct(current_write_pos, &data_size, sizeof(data_size)); + + if (buffer_id == 0) /* first buffer */ + data_size += write_start_event(trace, channel_handle, current_write_pos, start_tsc, using_tsc); + + return (int)data_size; +} + +/** + * buffer_end_callback - called at the end of a sub-buffer + * @channel_handle: the channel id + * @current_write_pos: position in sub-buffer of end of data + * @end_of_buffer: the position of the end of the sub-buffer + * @end_time: the timestamp associated with the end of the sub-buffer + * @end_tsc: the TSC associated with the end_time, if using_tsc + * @using_tsc: boolean, indicates whether end_tsc is valid + * + * This is the relayfs buffer_end() callback implementation for + * the tracer. We write the end event directly to the address + * contained in the current_write_pos param. We also calculate + * the 'size_lost' or unused bytes at the end of the sub-buffer + * and write that value to the very end of the sub-buffer for + * post-processing. Of course we reserved the number of bytes + * we're writing when we opened the channel, which is the number + * we return. + */ +static int buffer_end_callback(int channel_handle, + char * current_write_pos, + char * end_of_buffer, + struct timeval end_time, + u32 end_tsc, + int using_tsc) +{ + ltt_buffer_end end_buffer_event; + u8 event_id; + u32 time_delta; + char* init_write_pos = current_write_pos; + uint16_t data_size; + u32 size_lost; + u8 cpu_id; + struct ltt_trace_struct *trace; + + end_buffer_event.time = end_time; + end_buffer_event.tsc = end_tsc; + + cpu_id = (u8)ltt_channel_cpuid(channel_handle); + trace = ltt_channel_trace(channel_handle); + if (!trace) + return 0; + + if (trace->log_cpuid == 1) + relay_write_direct(current_write_pos, &cpu_id, sizeof(cpu_id)); + + event_id = LTT_EV_BUFFER_END; + relay_write_direct(current_write_pos, &event_id, sizeof(event_id)); + + time_delta = switch_time_delta(end_tsc, using_tsc); + relay_write_direct(current_write_pos, &time_delta, sizeof(time_delta)); + + relay_write_direct(current_write_pos, &end_buffer_event, sizeof(end_buffer_event)); + + data_size = sizeof(event_id) + sizeof(time_delta) + sizeof(end_buffer_event) + sizeof(data_size); + + relay_write_direct(current_write_pos, &data_size, sizeof(data_size)); + + /* size lost includes size of end buffer event */ + size_lost = end_of_buffer - init_write_pos; + *((u32 *) (end_of_buffer - sizeof(size_lost))) = size_lost; + + return (int)data_size; +} + +/** + * deliver_callback - called when data is ready for the tracer + * @channel_handle: the channel id + * @from: the start of the delivered data + * @len: the length of the delivered data + * + * This is the relayfs deliver() callback implementation for + * the tracer. We simply set the send_signal flag, which will + * be checked when the current write is finished, at which + * point the daemon will be signaled to read the buffer. + */ +void deliver_callback(int channel_handle, + char * from, + u32 len) +{ + struct ltt_trace_struct *trace; + int cpu_id; + + trace = ltt_channel_trace(channel_handle); + if (!trace) + return; + + cpu_id = ltt_channel_cpuid(channel_handle); + if (cpu_id == -1) + return; + + set_bit(cpu_id, &trace->buffer_switches_pending); +} + +/** + * fileop_notify - called when change to trace file status + * @rchan_id: the rchan id + * @filp: the file + * @fileop: the file operation + * + * This is the relayfs fileop_notify() callback implementation for + * the tracer. We use it to take care of trace file mapping and + * unmapping tasks. + */ +static int fileop_notify (int rchan_id, + struct file *filp, + enum relay_fileop fileop) +{ + struct rchan_reader *map_reader; + struct rchan_reader *open_file_reader; + struct rchan *rchan; + u8 cpu_id; + int trace_handle; + + trace_handle = ltt_channel_trace_handle(rchan_id); + if (trace_handle == -1) + return 0; + + if (fileop == RELAY_FILE_MAP) { + cpu_id = (u8)ltt_channel_cpuid(rchan_id); + open_file_reader = (struct rchan_reader *)filp->private_data; + rchan = open_file_reader->rchan; + if (atomic_read(&rchan->mapped)) + return -EBUSY; + map_reader = add_map_reader(rchan_id); + trace_channel_reader(trace_handle, cpu_id) = map_reader; + } + else if (fileop == RELAY_FILE_UNMAP) { + cpu_id = (u8)ltt_channel_cpuid(rchan_id); + remove_map_reader(trace_channel_reader(trace_handle, cpu_id)); + trace_channel_reader(trace_handle, cpu_id) = NULL; + } + + return 0; +} + +static struct rchan_callbacks ltt_callbacks = { + .buffer_start = buffer_start_callback, + .buffer_end = buffer_end_callback, + .deliver = deliver_callback, + .fileop_notify = fileop_notify, + .ioctl = ltt_ioctl, +}; + +/* + * Procfs kernel-user interface + */ + +/** + * proc_read_relayfs_path - procfs read callback for relayfs_path attr + */ +static int proc_read_relayfs_path(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return sprintf(page, "%s", relayfs_path); +} + +/** + * proc_write_relayfs_path - procfs write callback for relayfs_path attr + * + * Sets the path to the trace files within relayfs for the current trace. + */ +static int proc_write_relayfs_path(struct file *filp, const char *buffer, + unsigned long count, void *data) +{ + unsigned long len; + + if (count > PATH_MAX) + len = PATH_MAX; + else + len = count; + + if (copy_from_user(relayfs_path, buffer, len)) + return -EFAULT; + + if (len != PATH_MAX) + relayfs_path[len] = '\0'; + + return len; +} + +/** + * populate_handle_proc_dir - populate proc dir with trace attributes + * @trace_handle: the trace handle for this trace run + * @handle_dir: the directory to populate + * + * This function populates the handle dir with attribute files. + * + * Returns 0 if successful, negative if not. + */ +static int populate_handle_proc_dir(unsigned int trace_handle, + struct proc_dir_entry *handle_dir) +{ + struct proc_dir_entry * file_entry; + int err = 0; + + file_entry = create_proc_entry("relayfs_path", 0666, handle_dir); + + if (file_entry == NULL) { + err = -ENOMEM; + return err; + } + + file_entry->read_proc = proc_read_relayfs_path; + file_entry->write_proc = proc_write_relayfs_path; + file_entry->data = (void *)trace_handle; + file_entry->owner = THIS_MODULE; + + return err; +} + +/** + * create_handle_proc_dir - create proc dir for trace attributes + * @trace_handle: the trace handle for this trace run + * + * This function creates a proc dir to communicate trace attribute + * values between the daemon and the tracer. It also populates the + * new dir with the attribute files. + * + * Retruns the proc dir entry if successful, NULL otherwise. + */ +static struct proc_dir_entry *create_handle_proc_dir(unsigned int trace_handle) +{ + char handle_dir_name[22]; + struct proc_dir_entry *handle_dir; + + sprintf(handle_dir_name, "%u", trace_handle); + + handle_dir = proc_mkdir(handle_dir_name, ltt_proc_root_entry); + + if (handle_dir == NULL) + return NULL; + else + handle_dir->owner = THIS_MODULE; + + if (populate_handle_proc_dir(trace_handle, handle_dir)) { + remove_proc_entry(handle_dir_name, ltt_proc_root_entry); + handle_dir = NULL; + } + + return handle_dir; +} + +/** + * depopulate_handle_proc_dir - remove proc dir entries for handle_dir + * @handle_dir: the directory to depopulate + * + * This function removes the attribute files from the handle dir. + */ +static void depopulate_handle_proc_dir(struct proc_dir_entry *handle_dir) +{ + remove_proc_entry("relayfs_path", handle_dir); +} + +/** + * remove_handle_proc_dir - remove proc dir for trace attributes + * @handle_dir: the directory + * @trace_handle: the trace handle for this trace run + * + * This function removes a trace handle's proc dir. It first + * depopulates the dir of attribute files. + */ +static void remove_handle_proc_dir(struct proc_dir_entry *handle_dir, + unsigned int trace_handle) +{ + char handle_dir_name[22]; + + depopulate_handle_proc_dir(handle_dir); + + sprintf(handle_dir_name, "%u", trace_handle); + remove_proc_entry(handle_dir_name, ltt_proc_root_entry); +} + + +/* + * Initialization and finalization + */ + +static struct rchan_callbacks control_callbacks = { + .ioctl = ltt_ioctl, +}; + +/** + * create_control_channel - creates channel /mnt/relay/ltt/control + * + * Returns channel id on success, negative otherwise. + */ +static int create_control_channel(void) +{ + u32 bufsize, nbufs; + u32 channel_flags; + int control; + + sprintf(relay_file_name, "%s/%s", LTT_RELAYFS_ROOT, LTT_CONTROL_FILE); + + channel_flags = RELAY_DELIVERY_PACKET | RELAY_USAGE_GLOBAL; + channel_flags |= RELAY_SCHEME_ANY | RELAY_TIMESTAMP_ANY; + + bufsize = 4096; + nbufs = 4; + + control = relay_open(relay_file_name, bufsize, nbufs, channel_flags, &control_callbacks, + 0, 0, 0, 0, 0, 0, NULL, 0); + + return control; +} + +/** + * proc_read_init_ltt - procfs read callback for init attr + */ +static int proc_read_init_ltt(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return sprintf(page, "%d", control_channel == -1 ? 0 : 1); +} + +/** + * proc_write_init_ltt - procfs write callback for init attr + */ +static int proc_write_init_ltt(struct file *filp, const char *buffer, + unsigned long count, void *data) +{ + if (control_channel == -1) { + control_channel = create_control_channel(); + + if (control_channel < 0) + printk("LTT control channel creation failed, errcode: %d\n", control_channel); + else + printk("LTT control channel created\n"); + } + + return 1; +} + +/** + * remove_control_channel - destroys channel /mnt/relay/ltt/control + * + * Returns 0, negative otherwise. + */ +static int remove_control_channel(void) +{ + if (control_channel != -1) + return relay_close(control_channel); + + return -ENODEV; +} + +static int __init init_ltt(void) +{ + int i; + int err = 0; + struct proc_dir_entry *init_entry; + + ltt_proc_root_entry = proc_mkdir("ltt", NULL); + + if (ltt_proc_root_entry == NULL) + err = -ENOMEM; + else + ltt_proc_root_entry->owner = THIS_MODULE; + + control_channel = -1; + + init_entry = create_proc_entry("init", 0666, ltt_proc_root_entry); + if (init_entry == NULL) { + err = -ENOMEM; + return err; + } + + init_entry->read_proc = proc_read_init_ltt; + init_entry->write_proc = proc_write_init_ltt; + init_entry->owner = THIS_MODULE; + + for (i = 0; i < NR_TRACES; i++) + init_trace(¤t_traces[i]); + + return err; +} + +static void __exit exit_ltt(void) +{ + remove_proc_entry("init", ltt_proc_root_entry); + remove_proc_entry("ltt", NULL); + + remove_control_channel(); +} + +module_init(init_ltt) +module_exit(exit_ltt) + +EXPORT_SYMBOL(ltt_set_trace_config); +EXPORT_SYMBOL(ltt_get_trace_config); +EXPORT_SYMBOL(ltt_create_event); +EXPORT_SYMBOL(ltt_create_owned_event); +EXPORT_SYMBOL(ltt_destroy_event); +EXPORT_SYMBOL(ltt_destroy_owners_events); +EXPORT_SYMBOL(ltt_log_std_formatted_event); +EXPORT_SYMBOL(ltt_log_raw_event); +EXPORT_SYMBOL(ltt_log_event); +EXPORT_SYMBOL(syscall_entry_trace_active); +EXPORT_SYMBOL(syscall_exit_trace_active); +EXPORT_SYMBOL(ltt_flight_pause); +EXPORT_SYMBOL(ltt_flight_unpause); + +MODULE_AUTHOR("Karim Yaghmour, Tom Zanussi, Bob Wisniewski") +MODULE_DESCRIPTION("Linux Trace Toolkit kernel core") +MODULE_LICENSE("GPL"); diff -urpN linux-2.6.10-relayfs/kernel/Makefile linux-2.6.10-relayfs-ltt/kernel/Makefile --- linux-2.6.10-relayfs/kernel/Makefile 2004-12-24 16:34:26.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/kernel/Makefile 2005-01-13 22:21:56.000000000 -0500 @@ -17,6 +17,7 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_PM) += power/ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o +obj-$(CONFIG_LTT) += ltt-core.o obj-$(CONFIG_COMPAT) += compat.o obj-$(CONFIG_IKCONFIG) += configs.o obj-$(CONFIG_IKCONFIG_PROC) += configs.o diff -urpN linux-2.6.10-relayfs/kernel/sched.c linux-2.6.10-relayfs-ltt/kernel/sched.c --- linux-2.6.10-relayfs/kernel/sched.c 2004-12-24 16:35:24.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/kernel/sched.c 2005-01-13 22:21:51.000000000 -0500 @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -317,6 +318,8 @@ static runqueue_t *task_rq_lock(task_t * { struct runqueue *rq; + ltt_ev_process(LTT_EV_PROCESS_WAKEUP, p->pid, p->state); + repeat_lock_task: local_irq_save(*flags); rq = task_rq(p); @@ -2685,6 +2688,7 @@ switch_tasks: ++*switch_count; prepare_arch_switch(rq, next); + ltt_ev_schedchange(prev, next); prev = context_switch(rq, prev, next); barrier(); diff -urpN linux-2.6.10-relayfs/kernel/signal.c linux-2.6.10-relayfs-ltt/kernel/signal.c --- linux-2.6.10-relayfs/kernel/signal.c 2004-12-24 16:34:32.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/kernel/signal.c 2005-01-13 22:21:51.000000000 -0500 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -833,6 +834,8 @@ specific_send_sig_info(int sig, struct s if (sig_ignored(t, sig)) goto out; + ltt_ev_process(LTT_EV_PROCESS_SIGNAL, sig, t->pid); + /* Support queueing exactly one non-rt signal, so that we can get more detailed information about the cause of the signal. */ diff -urpN linux-2.6.10-relayfs/kernel/softirq.c linux-2.6.10-relayfs-ltt/kernel/softirq.c --- linux-2.6.10-relayfs/kernel/softirq.c 2004-12-24 16:34:26.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/kernel/softirq.c 2005-01-13 22:21:51.000000000 -0500 @@ -16,6 +16,7 @@ #include #include #include +#include #include /* @@ -92,6 +93,7 @@ restart: do { if (pending & 1) { + ltt_ev_soft_irq(LTT_EV_SOFT_IRQ_SOFT_IRQ, (h - softirq_vec)); h->action(h); rcu_bh_qsctr_inc(cpu); } @@ -246,6 +248,9 @@ static void tasklet_action(struct softir if (!atomic_read(&t->count)) { if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) BUG(); + + ltt_ev_soft_irq(LTT_EV_SOFT_IRQ_TASKLET_ACTION, (unsigned long) (t->func)); + t->func(t->data); tasklet_unlock(t); continue; @@ -279,6 +284,9 @@ static void tasklet_hi_action(struct sof if (!atomic_read(&t->count)) { if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) BUG(); + + ltt_ev_soft_irq(LTT_EV_SOFT_IRQ_TASKLET_HI_ACTION, (unsigned long) (t->func)); + t->func(t->data); tasklet_unlock(t); continue; diff -urpN linux-2.6.10-relayfs/kernel/timer.c linux-2.6.10-relayfs-ltt/kernel/timer.c --- linux-2.6.10-relayfs/kernel/timer.c 2004-12-24 16:35:24.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/kernel/timer.c 2005-01-13 22:21:51.000000000 -0500 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -923,6 +924,8 @@ static void run_timer_softirq(struct sof { tvec_base_t *base = &__get_cpu_var(tvec_bases); + ltt_ev(LTT_EV_KERNEL_TIMER, NULL); + if (time_after_eq(jiffies, base->timer_jiffies)) __run_timers(base); } @@ -1081,6 +1084,7 @@ asmlinkage long sys_getegid(void) static void process_timeout(unsigned long __data) { + ltt_ev_timer(LTT_EV_TIMER_EXPIRED, 0, 0, 0); wake_up_process((task_t *)__data); } diff -urpN linux-2.6.10-relayfs/MAINTAINERS linux-2.6.10-relayfs-ltt/MAINTAINERS --- linux-2.6.10-relayfs/MAINTAINERS 2004-12-24 16:35:00.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/MAINTAINERS 2005-01-13 22:21:56.000000000 -0500 @@ -1363,6 +1363,13 @@ L: linux-security-module@wirex.com W: http://lsm.immunix.org S: Supported +LINUX TRACE TOOLKIT +P: Karim Yaghmour +M: karim@opersys.com +W: http://www.opersys.com/LTT +L: ltt-dev@listserv.shafik.org +S: Maintained + LM83 HARDWARE MONITOR DRIVER P: Jean Delvare M: khali@linux-fr.org diff -urpN linux-2.6.10-relayfs/mm/filemap.c linux-2.6.10-relayfs-ltt/mm/filemap.c --- linux-2.6.10-relayfs/mm/filemap.c 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/mm/filemap.c 2005-01-13 22:21:51.000000000 -0500 @@ -28,6 +28,7 @@ #include #include #include +#include /* * This is needed for the following functions: * - try_to_release_page @@ -402,9 +403,13 @@ void fastcall wait_on_page_bit(struct pa { DEFINE_WAIT_BIT(wait, &page->flags, bit_nr); + ltt_ev_memory(LTT_EV_MEMORY_PAGE_WAIT_START, 0); + if (test_bit(bit_nr, &page->flags)) __wait_on_bit(page_waitqueue(page), &wait, sync_page, TASK_UNINTERRUPTIBLE); + + ltt_ev_memory(LTT_EV_MEMORY_PAGE_WAIT_END, 0); } EXPORT_SYMBOL(wait_on_page_bit); diff -urpN linux-2.6.10-relayfs/mm/memory.c linux-2.6.10-relayfs-ltt/mm/memory.c --- linux-2.6.10-relayfs/mm/memory.c 2004-12-24 16:34:44.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/mm/memory.c 2005-01-13 22:21:51.000000000 -0500 @@ -47,6 +47,9 @@ #include #include +#include +#include + #include #include #include @@ -1346,6 +1349,7 @@ static int do_swap_page(struct mm_struct spin_unlock(&mm->page_table_lock); page = lookup_swap_cache(entry); if (!page) { + ltt_ev_memory(LTT_EV_MEMORY_SWAP_IN, address); swapin_readahead(entry, address, vma); page = read_swap_cache_async(entry, vma, address); if (!page) { diff -urpN linux-2.6.10-relayfs/mm/page_alloc.c linux-2.6.10-relayfs-ltt/mm/page_alloc.c --- linux-2.6.10-relayfs/mm/page_alloc.c 2004-12-24 16:33:51.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/mm/page_alloc.c 2005-01-13 22:21:51.000000000 -0500 @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -278,6 +279,8 @@ void __free_pages_ok(struct page *page, LIST_HEAD(list); int i; + ltt_ev_memory(LTT_EV_MEMORY_PAGE_FREE, order); + arch_free_page(page, order); mod_page_state(pgfree, 1 << order); @@ -752,6 +755,7 @@ fastcall unsigned long __get_free_pages( page = alloc_pages(gfp_mask, order); if (!page) return 0; + ltt_ev_memory(LTT_EV_MEMORY_PAGE_ALLOC, order); return (unsigned long) page_address(page); } diff -urpN linux-2.6.10-relayfs/mm/page_io.c linux-2.6.10-relayfs-ltt/mm/page_io.c --- linux-2.6.10-relayfs/mm/page_io.c 2004-12-24 16:33:59.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/mm/page_io.c 2005-01-13 22:21:51.000000000 -0500 @@ -17,6 +17,7 @@ #include #include #include +#include #include static struct bio *get_swap_bio(int gfp_flags, pgoff_t index, @@ -103,6 +104,7 @@ int swap_writepage(struct page *page, st inc_page_state(pswpout); set_page_writeback(page); unlock_page(page); + ltt_ev_memory(LTT_EV_MEMORY_SWAP_OUT, (unsigned long) page); submit_bio(rw, bio); out: return ret; diff -urpN linux-2.6.10-relayfs/net/core/dev.c linux-2.6.10-relayfs-ltt/net/core/dev.c --- linux-2.6.10-relayfs/net/core/dev.c 2004-12-24 16:34:45.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/net/core/dev.c 2005-01-13 22:21:51.000000000 -0500 @@ -107,6 +107,7 @@ #include #include #include +#include #include #ifdef CONFIG_NET_RADIO #include /* Note : will define WIRELESS_EXT */ @@ -1245,6 +1246,8 @@ int dev_queue_xmit(struct sk_buff *skb) if (skb_checksum_help(skb, 0)) goto out_kfree_skb; + ltt_ev_network(LTT_EV_NETWORK_PACKET_OUT, skb->protocol); + /* Disable soft irqs for various locks below. Also * stops preemption for RCU. */ @@ -1642,6 +1645,8 @@ int netif_receive_skb(struct sk_buff *sk __get_cpu_var(netdev_rx_stat).total++; + ltt_ev_network(LTT_EV_NETWORK_PACKET_IN, skb->protocol); + skb->h.raw = skb->nh.raw = skb->data; skb->mac_len = skb->nh.raw - skb->mac.raw; diff -urpN linux-2.6.10-relayfs/net/socket.c linux-2.6.10-relayfs-ltt/net/socket.c --- linux-2.6.10-relayfs/net/socket.c 2004-12-24 16:34:31.000000000 -0500 +++ linux-2.6.10-relayfs-ltt/net/socket.c 2005-01-13 22:21:51.000000000 -0500 @@ -81,6 +81,7 @@ #include #include #include +#include #ifdef CONFIG_NET_RADIO #include /* Note : will define WIRELESS_EXT */ @@ -551,6 +552,8 @@ int sock_sendmsg(struct socket *sock, st struct sock_iocb siocb; int ret; + ltt_ev_socket(LTT_EV_SOCKET_SEND, sock->type, size); + init_sync_kiocb(&iocb, NULL); iocb.private = &siocb; ret = __sock_sendmsg(&iocb, sock, msg, size); @@ -603,6 +606,8 @@ int sock_recvmsg(struct socket *sock, st struct sock_iocb siocb; int ret; + ltt_ev_socket(LTT_EV_SOCKET_RECEIVE, sock->type, size); + init_sync_kiocb(&iocb, NULL); iocb.private = &siocb; ret = __sock_recvmsg(&iocb, sock, msg, size, flags); @@ -1197,6 +1202,8 @@ asmlinkage long sys_socket(int family, i if (retval < 0) goto out_release; + ltt_ev_socket(LTT_EV_SOCKET_CREATE, retval, type); + out: /* It may be already another descriptor 8) Not kernel problem. */ return retval; @@ -1916,6 +1923,8 @@ asmlinkage long sys_socketcall(int call, a0=a[0]; a1=a[1]; + + ltt_ev_socket(LTT_EV_SOCKET_CALL, call, a0); switch(call) {