[UPDATE/RFC/PATCH] Linux Trace Toolkit

From: Karim Yaghmour (karym@opersys.com)
Date: Mon Mar 27 2000 - 13:40:43 EST


UPDATE:
This is to inform you that a new version of the Linux Trace Toolkit has
been released. Version 0.9.1 marks a mile-stone because of it's ability
to manipulate very large traces and it's usage of memory mapping to reduce
data transfers from the kernel to user-space. Most of the changes are
not visible (the command-line options and interface have not changed),
but the underlying mechanisms have been completely re-written. Yet, the
architecture remains the same.

RFC:
Given the insight LTT allows into Linux' functionnality, it's low-overhead,
it's modularity and it's flexibility, it would be very interesting to see
the trace functionnality incorporated into the standard kernel tree. That said,
the modifications into the kernel's code are minimal and completely
configurable. That is, you only need to enable or disable the kernel tracing
option in the configuration menu in order to include or remove the tracing
facilities from the kernel. The said patch has been included with this message
to generate discussion. It would be important to stress that unlike the
kernel debugger patch or a profiling patch, this patch does not strictly
serve kernel developers. It is actually meant to be used by developpers and
system administrators who would like to get more insight into the system's
behavior. Therefore the public is quite broad. As has been suggested by many,
this patch can also serve as a basis for an enhanced security auditing system
or an intrusion detection scheme. The hooks are there or are quite easy to
implement. I would very much like to hear what members of the list think
about this issue. (I have no specific kernel version in sight for including
this patch. 2.4 would be ideal and it would actually be easy since the patch
doesn't have that much influence on it's surroundings, but I'll leave this
one for Linus.)

Take a look at LTT's web page :
  http://www.opersys.com/LTT

Best Regards.

===================================================
                 Karim Yaghmour
               karym@opersys.com
          Operating System Consultant
 (Linux kernel, real-time and distributed systems)
===================================================

diff -urN linux/Documentation/Configure.help linux-2.2.14/Documentation/Configure.help
--- linux/Documentation/Configure.help Tue Jan 4 13:12:10 2000
+++ linux-2.2.14/Documentation/Configure.help Mon Mar 27 02:23:39 2000
@@ -12039,6 +12039,43 @@
 
   If you do not have any Quicknet telephony cards, you can safely
   ignore this option.
+
+Kernel events tracing support
+CONFIG_TRACE
+ It is possible for the kernel to log important events to a tracing
+ driver. Doing so, enables the use of the generated traces in order
+ to reconstruct the dynamic behavior of the kernel, and hence the
+ whole system.
+
+ The tracing process contains 4 parts :
+ 1) The logging of events by key parts of the kernel.
+ 2) The trace driver that keeps the events in a data buffer.
+ 3) A trace daemon that opens the trace driver and is notified
+ every time there is a certain quantity of data to read
+ from the trace driver (using SIG_IO).
+ 4) A trace event data decoder that reads the accumulated data
+ and formats it in a human-readable format.
+
+ If you say Y or M here, the first part of the tracing process will
+ always take place. That is, critical parts of the kernel will call
+ upon the kernel tracing function. The data generated doesn't go
+ any further until a trace driver registers himself as such with the
+ kernel. Therefore, if you answer Y, then the driver will be part of
+ the kernel and the events will always proceed onto the driver and
+ if you say M, then the events will only proceed onto the driver when
+ it's module is loaded. Note that event's aren't logged in the driver
+ until the profiling daemon opens the device, configures it and
+ issues the "start" command through ioctl().
+
+ The impact of a fully functionnal system (kernel event logging +
+ driver event copying + active trace daemon) is of 2.5% for core events.
+ This means that for a task that took 100 seconds on a normal system, it
+ will take 102.5 seconds on a traced system. This is very low compared
+ to other profiling or tracing methods.
+
+ For more information on kernel tracing, the trace daemon or the event
+ decoder, please check the following address :
+ http://www.opersys.com/LTT
  
 #
 # A couple of things I keep forgetting:
diff -urN linux/Makefile linux-2.2.14/Makefile
--- linux/Makefile Tue Jan 4 13:12:10 2000
+++ linux-2.2.14/Makefile Mon Mar 27 02:24:48 2000
@@ -206,6 +206,10 @@
 DRIVERS := $(DRIVERS) drivers/telephony/telephony.a
 endif
 
+ifeq ($(CONFIG_TRACE),y)
+DRIVERS := $(DRIVERS) drivers/trace/tracer.a
+endif
+
 include arch/$(ARCH)/Makefile
 
 .S.s:
diff -urN linux/arch/i386/config.in linux-2.2.14/arch/i386/config.in
--- linux/arch/i386/config.in Tue Jan 4 13:12:11 2000
+++ linux-2.2.14/arch/i386/config.in Mon Mar 27 02:26:21 2000
@@ -201,6 +201,11 @@
 endmenu
 
 mainmenu_option next_comment
+comment 'Kernel tracing'
+tristate 'Kernel events tracing support' CONFIG_TRACE
+endmenu
+
+mainmenu_option next_comment
 comment 'Kernel hacking'
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
diff -urN linux/arch/i386/kernel/entry.S linux-2.2.14/arch/i386/kernel/entry.S
--- linux/arch/i386/kernel/entry.S Fri Apr 30 11:13:37 1999
+++ linux-2.2.14/arch/i386/kernel/entry.S Mon Mar 27 02:27:57 2000
@@ -176,8 +176,22 @@
         jae badsys
         testb $0x20,flags(%ebx) # PF_TRACESYS
         jne tracesys
+
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+ movl %esp, %eax # copy the stack pointer
+ pushl %eax # pass the stack pointer copy
+ call SYMBOL_NAME(trace_real_syscall_entry)
+ addl $4,%esp # return stack to state before pass
+ movl ORIG_EAX(%esp),%eax # restore eax to it's original content
+#endif
+
         call *SYMBOL_NAME(sys_call_table)(,%eax,4)
         movl %eax,EAX(%esp) # save the return value
+
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+ call SYMBOL_NAME(trace_real_syscall_exit)
+#endif
+
         ALIGN
         .globl ret_from_sys_call
         .globl ret_from_intr
diff -urN linux/arch/i386/kernel/irq.c linux-2.2.14/arch/i386/kernel/irq.c
--- linux/arch/i386/kernel/irq.c Tue Oct 26 20:53:39 1999
+++ linux-2.2.14/arch/i386/kernel/irq.c Mon Mar 27 02:29:54 2000
@@ -31,6 +31,8 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -235,6 +237,8 @@
         struct irqaction * action;
         irq_desc_t *desc = irq_desc + irq;
 
+ TRACE_IRQ_ENTRY(irq, !(user_mode(regs)));
+
         spin_lock(&irq_controller_lock);
         {
                 unsigned int status;
@@ -263,6 +267,8 @@
                         enable_8259A_irq(irq);
         }
         spin_unlock(&irq_controller_lock);
+
+ TRACE_EVENT(TRACE_EV_IRQ_EXIT, NULL);
 }
 
 /*
diff -urN linux/arch/i386/kernel/process.c linux-2.2.14/arch/i386/kernel/process.c
--- linux/arch/i386/kernel/process.c Tue Oct 26 20:53:39 1999
+++ linux-2.2.14/arch/i386/kernel/process.c Mon Mar 27 02:31:45 2000
@@ -35,6 +35,8 @@
 #include <linux/apm_bios.h>
 #endif
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -524,6 +526,10 @@
                  "r" (arg), "r" (fn),
                  "b" (flags | CLONE_VM)
                 : "memory");
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+ if (retval > 0)
+ TRACE_PROCESS(TRACE_EV_PROCESS_KTHREAD, retval, (int) fn);
+#endif
         return retval;
 }
 
diff -urN linux/arch/i386/kernel/sys_i386.c linux-2.2.14/arch/i386/kernel/sys_i386.c
--- linux/arch/i386/kernel/sys_i386.c Thu Dec 17 19:27:35 1998
+++ linux-2.2.14/arch/i386/kernel/sys_i386.c Mon Mar 27 02:32:48 2000
@@ -19,6 +19,8 @@
 #include <linux/file.h>
 #include <linux/utsname.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
 
@@ -115,6 +117,8 @@
 
         version = call >> 16; /* hack for backward compatibility */
         call &= 0xffff;
+
+ TRACE_IPC(TRACE_EV_IPC_CALL, call, first);
 
         if (call <= SEMCTL)
                 switch (call) {
diff -urN linux/arch/i386/kernel/traps.c linux-2.2.14/arch/i386/kernel/traps.c
--- linux/arch/i386/kernel/traps.c Tue Feb 16 17:20:05 1999
+++ linux-2.2.14/arch/i386/kernel/traps.c Mon Mar 27 02:41:29 2000
@@ -21,6 +21,8 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 
+#include <linux/trace.h>
+
 #ifdef CONFIG_MCA
 #include <linux/mca.h>
 #include <asm/processor.h>
@@ -67,8 +69,10 @@
 { \
         tsk->tss.error_code = error_code; \
         tsk->tss.trap_no = trapnr; \
+ TRACE_TRAP_ENTRY(signr, regs->eip);\
         force_sig(signr, tsk); \
         die_if_no_fixup(str,regs,error_code); \
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); \
 }
 
 #define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \
@@ -82,8 +86,10 @@
         } \
         tsk->tss.error_code = error_code; \
         tsk->tss.trap_no = trapnr; \
+ TRACE_TRAP_ENTRY(signr, regs->eip);\
         force_sig(signr, tsk); \
         die_if_kernel(str,regs,error_code); \
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL); \
 out: \
         unlock_kernel(); \
 }
@@ -193,6 +199,82 @@
         printk("\n");
 }
 
+/* Trace related code */
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+asmlinkage void trace_real_syscall_entry(struct pt_regs * regs)
+{
+ int use_depth;
+ int use_bounds;
+ int depth = 0;
+ int seek_depth;
+ unsigned long lower_bound;
+ unsigned long upper_bound;
+ unsigned long addr;
+ unsigned long* stack;
+ trace_syscall_entry trace_syscall_event;
+
+ /* Set the syscall ID */
+ trace_syscall_event.syscall_id = (uint8_t) regs->orig_eax;
+
+ /* Set the address in any case */
+ trace_syscall_event.address = regs->eip;
+
+ /* Are we in the kernel (This is a kernel thread)? */
+ if(!(regs->xcs & 3))
+ /* Don't go digining anywhere */
+ goto trace_syscall_end;
+
+ /* Get the trace configuration */
+ if(trace_get_config(&use_depth,
+ &use_bounds,
+ &seek_depth,
+ (void*)&lower_bound,
+ (void*)&upper_bound) < 0)
+ goto trace_syscall_end;
+
+ /* Do we have to search for an eip address range */
+ if((use_depth == 1) || (use_bounds == 1))
+ {
+ /* Start at the top of the stack (bottom address since stacks grow downward) */
+ stack = (unsigned long*) regs->esp;
+
+ /* Keep on going until we reach the end of the process' stack limit (wherever it may be) */
+ while(!get_user(addr, stack))
+ {
+ /* Does this LOOK LIKE an address in the program */
+ if((addr > current->mm->start_code)
+ &&(addr < current->mm->end_code))
+ {
+ /* Does this address fit the description */
+ if(((use_depth == 1) && (depth == seek_depth))
+ ||((use_bounds == 1) && (addr > lower_bound) && (addr < upper_bound)))
+ {
+ /* Set the address */
+ trace_syscall_event.address = addr;
+
+ /* We're done */
+ goto trace_syscall_end;
+ }
+ else
+ /* We're one depth more */
+ depth++;
+ }
+ /* Go on to the next address */
+ stack++;
+ }
+ }
+
+trace_syscall_end:
+ /* Trace the event */
+ trace_event(TRACE_EV_SYSCALL_ENTRY, &trace_syscall_event);
+}
+
+asmlinkage void trace_real_syscall_exit(void)
+{
+ trace_event(TRACE_EV_SYSCALL_EXIT, NULL);
+}
+#endif /* (CONFIG_TRACE || CONFIG_TRACE_MODULE) */
+
 spinlock_t die_lock;
 
 void die(const char * str, struct pt_regs * regs, long err)
@@ -264,12 +346,16 @@
 
         current->tss.error_code = error_code;
         current->tss.trap_no = 13;
+ TRACE_TRAP_ENTRY(13, regs->eip);
         force_sig(SIGSEGV, current);
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
         return;
 
 gp_in_vm86:
         lock_kernel();
+ TRACE_TRAP_ENTRY(13, regs->eip);
         handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
         unlock_kernel();
         return;
 
@@ -334,6 +420,8 @@
                 io_check_error(reason, regs);
         if (!(reason & 0xc0))
                 unknown_nmi_error(reason, regs);
+ TRACE_TRAP_ENTRY(2, regs->eip);
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 }
 
 /*
@@ -387,12 +475,16 @@
         /* Ok, finally something we can handle */
         tsk->tss.trap_no = 1;
         tsk->tss.error_code = error_code;
+ TRACE_TRAP_ENTRY(1, regs->eip);
         force_sig(SIGTRAP, tsk);
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
         return;
 
 debug_vm86:
         lock_kernel();
+ TRACE_TRAP_ENTRY(1, regs->eip);
         handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
         unlock_kernel();
         return;
 
@@ -429,17 +521,21 @@
 
 asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
 {
+ TRACE_TRAP_ENTRY(16, regs->eip);
         ignore_irq13 = 1;
         math_error();
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 }
 
 asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
                                           long error_code)
 {
+ TRACE_TRAP_ENTRY(16, regs->eip);
 #if 0
         /* No need to warn about this any longer. */
         printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
 #endif
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 }
 
 /*
@@ -472,8 +568,10 @@
         lock_kernel();
         printk("math-emulation not enabled and no coprocessor found.\n");
         printk("killing %s.\n",current->comm);
+ TRACE_TRAP_ENTRY(7, 0);
         force_sig(SIGFPE,current);
         schedule();
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
         unlock_kernel();
 }
 
diff -urN linux/arch/i386/mm/fault.c linux-2.2.14/arch/i386/mm/fault.c
--- linux/arch/i386/mm/fault.c Tue Jan 4 13:12:11 2000
+++ linux-2.2.14/arch/i386/mm/fault.c Mon Mar 27 02:46:42 2000
@@ -17,6 +17,8 @@
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 
+#include <linux/trace.h>
+
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -124,6 +126,8 @@
         tsk = current;
         mm = tsk->mm;
 
+ TRACE_TRAP_ENTRY(14, regs->eip);
+
         /*
          * If we're in an interrupt or have no user
          * context, we must not take the fault..
@@ -200,6 +204,7 @@
                         tsk->tss.screen_bitmap |= 1 << bit;
         }
         up(&mm->mmap_sem);
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
         return;
 
 /*
@@ -215,6 +220,7 @@
                 tsk->tss.error_code = error_code;
                 tsk->tss.trap_no = 14;
                 force_sig(SIGSEGV, tsk);
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
                 return;
         }
 
@@ -228,6 +234,7 @@
 
                 if (nr == 6) {
                         do_invalid_op(regs, 0);
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
                         return;
                 }
         }
@@ -236,6 +243,7 @@
         /* Are we prepared to handle this kernel fault? */
         if ((fixup = search_exception_table(regs->eip)) != 0) {
                 regs->eip = fixup;
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
                 return;
         }
 
@@ -324,4 +332,6 @@
         /* Kernel mode? Handle exceptions or die */
         if (!(error_code & 4))
                 goto no_context;
+
+ TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 }
diff -urN linux/drivers/Makefile linux-2.2.14/drivers/Makefile
--- linux/drivers/Makefile Tue Jan 4 13:12:13 2000
+++ linux-2.2.14/drivers/Makefile Mon Mar 27 02:48:08 2000
@@ -62,6 +62,16 @@
 MOD_SUB_DIRS += sgi
 endif
 
+# Is the trace module enabled
+ifeq ($(CONFIG_TRACE),y)
+SUB_DIRS += trace
+ALL_SUB_DIRS += trace
+else
+ ifeq ($(CONFIG_TRACE),m)
+ MOD_SUB_DIRS += trace
+ endif
+endif
+
 # If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel,
 # but some of the low-level things may also be modules.
 ifeq ($(CONFIG_SCSI),y)
diff -urN linux/drivers/trace/Makefile linux-2.2.14/drivers/trace/Makefile
--- linux/drivers/trace/Makefile Wed Dec 31 19:00:00 1969
+++ linux-2.2.14/drivers/trace/Makefile Mon Mar 27 02:19:54 2000
@@ -0,0 +1,30 @@
+#
+# Makefile for the kernel tracing drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET :=
+M_OBJS :=
+L_OBJS :=
+
+# Is it loaded as a module or as part of the kernel
+ifeq ($(CONFIG_TRACE),y)
+L_OBJS += tracer.o
+L_TARGET += tracer.a
+else
+ ifeq ($(CONFIG_TRACE),m)
+ M_OBJS += tracer.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
diff -urN linux/drivers/trace/tracer.c linux-2.2.14/drivers/trace/tracer.c
--- linux/drivers/trace/tracer.c Wed Dec 31 19:00:00 1969
+++ linux-2.2.14/drivers/trace/tracer.c Mon Mar 27 02:19:54 2000
@@ -0,0 +1,1162 @@
+/*****************************************************************
+ * File : tracer.c
+ * Description :
+ * Contains the code for the kernel tracing driver (tracer
+ * for short).
+ * Author :
+ * Karim Yaghmour
+ * Date :
+ * 13/03/00, Modified tracer so that the daemon mmaps the
+ * tracer's buffers in it's address space rather
+ * than use "read".
+ * 26/01/00, Added support for standardized buffer sizes and
+ * extensibility of events.
+ * 01/10/99, Modified tracer in order to used double-buffering.
+ * 28/09/99, Adding tracer configuration support.
+ * 09/09/99, Chaging the format of an event record in order to
+ * reduce the size of the traces.
+ * 04/03/99, Initial typing.
+ * Note :
+ * The sizes of the variables used to store the details of an
+ * event are planned for a system who gets at least one clock
+ * tick every 10milli-seconds. There has to be at least one
+ * event every 2^32-1 microseconds, otherwise the size of the
+ * variable holding the time doesn't work anymore.
+ *****************************************************************/
+
+/* Module and initialization stuff */
+#include <linux/module.h>
+#include <linux/init.h>
+
+/* Necessary includes */
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/trace.h>
+#include <asm/io.h>
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+/* Local defintions */
+#include "tracer.h"
+
+/* Local variables */
+/* Driver */
+static int sMajorNumber; /* Major number of the tracer */
+static int sOpenCount; /* Number of times device is open */
+/* Locking */
+static int sTracLock; /* Tracer lock used to lock primary buffer */
+static spinlock_t sSpinLock; /* Spinlock in order to lock kernel */
+/* Daemon */
+static int sSignalSent; /* A signal has been sent to the daemon */
+static struct task_struct* sDaemonTaskStruct; /* Task structure of the tracer daemon */
+/* Tracer configuration */
+static int sTracerStarted; /* Is the tracer started */
+static trace_event_mask sTracedEvents; /* Bit-field of events being traced */
+static trace_event_mask sLogEventDetailsMask; /* Log the details of the events mask */
+static int sLogCPUID; /* Log the CPUID associated with each event */
+static int sUseSyscallEIPBounds; /* Use adress bounds to fetch the EIP where call is made */
+static int sLowerEIPBoundSet; /* The lower bound EIP has been set */
+static int sUpperEIPBoundSet; /* The upper bound EIP has been set */
+static void* sLowerEIPBound; /* The lower bound EIP */
+static void* sUpperEIPBound; /* The upper bound EIP */
+static int sTracingPID; /* Tracing only the events for one pid */
+static int sTracingPGRP; /* Tracing only the events for one process group */
+static int sTracingGID; /* Tracing only the events for one gid */
+static int sTracingUID; /* Tracing only the events for one uid */
+static pid_t sTracedPID; /* PID being traced */
+static pid_t sTracedPGRP; /* Process group being traced */
+static gid_t sTracedGID; /* GID being traced */
+static uid_t sTracedUID; /* UID being traced */
+static int sSyscallEIPDepthSet; /* The call depth at which to fetch EIP has been set */
+static int sSyscallEIPDepth; /* The call depth at which to fetch the EIP */
+/* Event data buffers */
+static int sBufReadComplete; /* Number of buffers completely filled */
+static int sSizeReadIncomplete; /* Quantity of data read from incomplete buffers */
+static int sEventsLost; /* Number of events lost because of lack of buffer space */
+static uint32_t sBufSize; /* Buffer sizes */
+static int sBufSizeOrder; /* Buffer size order */
+static uint32_t sBufferID; /* Unique buffer ID */
+static char* sTracBuf = NULL; /* Trace buffer */
+static char* sWritBuf = NULL; /* Buffer used for writting */
+static char* sReadBuf = NULL; /* Buffer used for reading */
+static char* sWritBufEnd; /* End of write buffer */
+static char* sReadBufEnd; /* End of read buffer */
+static char* sWritPos; /* Current position for writting */
+static char* sReadLimit; /* Limit at which read should stop */
+static char* sWritLimit; /* Limit at which write should stop */
+/* Time */
+static struct timeval sBufferStartTime; /* The time at which the buffer was started */
+
+/* The size of the structures used to describe the events */
+static int sEventStructSize[TRACE_EV_MAX + 1] =
+{
+ sizeof(trace_start) /* TRACE_START */,
+ sizeof(trace_syscall_entry) /* TRACE_SYSCALL_ENTRY */,
+ 0 /* TRACE_SYSCALL_EXIT */,
+ sizeof(trace_trap_entry) /* TRACE_TRAP_ENTRY */,
+ 0 /* TRACE_TRAP_EXIT */,
+ sizeof(trace_irq_entry) /* TRACE_IRQ_ENTRY */,
+ 0 /* TRACE_IRQ_EXIT */,
+ sizeof(trace_schedchange) /* TRACE_SCHEDCHANGE */,
+ 0 /* TRACE_KERNEL_TIMER */,
+ sizeof(trace_bottom_half) /* TRACE_BOTTOM_HALF */,
+ sizeof(trace_process) /* TRACE_PROCESS */,
+ sizeof(trace_file_system) /* TRACE_FILE_SYSTEM */,
+ sizeof(trace_timer) /* TRACE_TIMER */,
+ sizeof(trace_memory) /* TRACE_MEMORY */,
+ sizeof(trace_socket) /* TRACE_SOCKET */,
+ sizeof(trace_ipc) /* TRACE_IPC */,
+ sizeof(trace_network) /* TRACE_NETWORK */,
+ sizeof(trace_buffer_start) /* TRACE_BUFFER_START */,
+ 0 /* TRACE_BUFFER_END */,
+ sizeof(trace_new_event) /* TRACE_NEW_EVENT */,
+ sizeof(trace_custom) /* TRACE_CUSTOM */
+};
+
+/* The file operations available for the tracer */
+static struct file_operations sTracerFileOps =
+{
+ NULL /* llseek */,
+ NULL /* read */,
+ NULL /* write */,
+ NULL /* readdir */,
+ NULL /* poll */,
+ &tracer_ioctl /* ioctl */,
+ &tracer_mmap /* mmap */,
+ &tracer_open /* open */,
+ NULL /* flush */,
+ &tracer_release /* release */,
+ &tracer_fsync /* fsync */,
+ NULL /* fasync */,
+ NULL /* check_media_change */,
+ NULL /* revalidate */,
+ NULL /* lock */
+};
+
+/**************************************************************
+ * Macro : tracer_write_to_buffer()
+ * Description :
+ * Writes data to the destination buffer and updates the
+ * begining the buffer write position.
+ **************************************************************/
+#define tracer_write_to_buffer(DEST, SRC, SIZE) \
+do\
+{\
+ memcpy(DEST, SRC, SIZE);\
+ DEST += SIZE;\
+} while(0);
+
+/**************************************************************
+ * Function : trace()
+ * Description : Tracing function per se.
+ * Parameters :
+ * pmEventID, ID of event as defined in linux/trace.h
+ * pmEventStruct, struct describing the event
+ * Return values :
+ * 0, if everything went OK (event got registered)
+ * -ENODEV, no tracing daemon opened the driver.
+ * -ENOMEM, no more memory to store events.
+ * -EBUSY, tracer not started yet.
+ * Note :
+ * The kernel has to be locked here because trace() could
+ * be called from an interrupt handling routine and from
+ * a process service routine.
+ **************************************************************/
+int trace(uint8_t pmEventID,
+ void* pmEventStruct)
+{
+ int lStringLen = 0; /* Length of string to be copied, if any */
+ char* lStringBeg = NULL; /* Begining of string to be copied */
+ int lSendSignal = FALSE; /* Should the daemon be summoned */
+ uint8_t lDataSize; /* Size of tracing data */
+ uint8_t lCPUID; /* CPUID of currently runing process */
+ struct siginfo lSigInfo; /* Signal information */
+ struct timeval lTime; /* Event time */
+ unsigned long int lFlags; /* CPU flags for lock */
+ trace_time_delta lTimeDelta; /* The time elapsed between now and the last event */
+
+ /* Is there a tracing daemon */
+ if(sDaemonTaskStruct == NULL)
+ return -ENODEV;
+
+ /* Do we trace the event */
+ if((sTracerStarted == TRUE) || (pmEventID == TRACE_EV_START) || (pmEventID == TRACE_EV_BUFFER_START))
+ goto TraceEvent;
+
+ /* We can't continue */
+ return -EBUSY;
+
+TraceEvent:
+
+ /* Are we monitoring this event */
+ if(!test_bit(pmEventID, &sTracedEvents))
+ return 0;
+
+ /* Always let the start event pass, whatever the IDs */
+ if((pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START))
+ {
+ /* Are we monitoring a particular process */
+ if((sTracingPID == TRUE) && (current->pid != sTracedPID))
+ return 0;
+
+ /* Are we monitoring a particular process group */
+ if((sTracingPGRP == TRUE) && (current->pgrp != sTracedPGRP))
+ return 0;
+
+ /* Are we monitoring the processes of a given group of users */
+ if((sTracingGID == TRUE) && (current->egid != sTracedGID))
+ return 0;
+
+ /* Are we monitoring the processes of a given user */
+ if((sTracingUID == TRUE) && (current->euid != sTracedUID))
+ return 0;
+ }
+
+ /* Compute size of tracing data */
+ lDataSize = sizeof(pmEventID) + sizeof(lTimeDelta) + sizeof(lDataSize);
+
+ /* Do we log the event details */
+ if(test_bit(pmEventID, &sLogEventDetailsMask))
+ {
+ /* Update the size of the data entry */
+ lDataSize += sEventStructSize[pmEventID];
+
+ /* Is there a file name in this */
+ if(pmEventID == TRACE_EV_FILE_SYSTEM)
+ if((((trace_file_system*) pmEventStruct)->event_sub_id == TRACE_EV_FILE_SYSTEM_EXEC)
+ || (((trace_file_system*) pmEventStruct)->event_sub_id == TRACE_EV_FILE_SYSTEM_OPEN))
+ {
+ /* Remember the string's beging and update size variables */
+ lStringBeg = ((trace_file_system*) pmEventStruct)->file_name;
+ lStringLen = ((trace_file_system*) pmEventStruct)->event_data2 + 1;
+ lDataSize += lStringLen;
+ }
+ }
+
+ /* Do we record the CPUID */
+ if((sLogCPUID == TRUE) && (pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START))
+ {
+ /* Remember the CPUID */
+ lCPUID = smp_processor_id();
+
+ /* Update the size of the data entry */
+ lDataSize += sizeof(lCPUID);
+ }
+
+ /* Lock the kernel */
+ spin_lock_irqsave(&sSpinLock, lFlags);
+
+ /* The following time calculations have to be done within the spinlock because
+ otherwise the event order could be inverted. */
+
+ /* Get the time of the event */
+ do_gettimeofday(&lTime);
+
+ /* Compute the time delta between this event and the time at which this buffer was started */
+ lTimeDelta = (lTime.tv_sec - sBufferStartTime.tv_sec) * 1000000
+ + (lTime.tv_usec - sBufferStartTime.tv_usec);
+
+ /* Is there enough space left in the write buffer */
+ if(sWritPos + lDataSize > sWritLimit)
+ {
+ /* Have we already switched buffers and informed the daemon of it */
+ if(sSignalSent == TRUE)
+ {
+ /* We've lost another event */
+ sEventsLost++;
+
+ /* Bye, bye, now */
+ spin_unlock_irqrestore(&sSpinLock, lFlags);
+ return -ENOMEM;
+ }
+
+ /* We need to inform the daemon */
+ lSendSignal = TRUE;
+
+ /* Switch buffers */
+ tracer_switch_buffers(lTime);
+
+ /* Recompute the time delta since sBufferStartTime has changed because of the buffer change */
+ lTimeDelta = (lTime.tv_sec - sBufferStartTime.tv_sec) * 1000000
+ + (lTime.tv_usec - sBufferStartTime.tv_usec);
+ }
+
+ /* Write the CPUID to the tracing buffer, if required */
+ if((sLogCPUID == TRUE) && (pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START))
+ tracer_write_to_buffer(sWritPos,
+ &lCPUID,
+ sizeof(lCPUID));
+
+ /* Write event type to tracing buffer */
+ tracer_write_to_buffer(sWritPos,
+ &pmEventID,
+ sizeof(pmEventID));
+
+ /* Write event time delta to tracing buffer */
+ tracer_write_to_buffer(sWritPos,
+ &lTimeDelta,
+ sizeof(lTimeDelta));
+
+ /* Do we log event details */
+ if(test_bit(pmEventID, &sLogEventDetailsMask))
+ {
+ /* Write event structure */
+ tracer_write_to_buffer(sWritPos,
+ pmEventStruct,
+ sEventStructSize[pmEventID]);
+
+ /* Write string if any */
+ if(lStringLen)
+ tracer_write_to_buffer(sWritPos,
+ lStringBeg,
+ lStringLen);
+ }
+
+ /* Write the length of the event description */
+ tracer_write_to_buffer(sWritPos,
+ &lDataSize,
+ sizeof(lDataSize));
+
+ /* Should the tracing daemon be notified */
+ if(lSendSignal == TRUE)
+ {
+ /* Remember that a signal has been sent */
+ sSignalSent = TRUE;
+
+ /* Unlock the kernel */
+ spin_unlock_irqrestore(&sSpinLock, lFlags);
+
+ /* Setup signal information */
+ lSigInfo.si_signo = SIGIO;
+ lSigInfo.si_errno = 0;
+ lSigInfo.si_code = SI_KERNEL;
+
+ /* DEBUG */
+#if 0
+ printk("<1> Sending SIGIO to %d \n", sDaemonTaskStruct->pid);
+#endif
+
+ /* Signal the tracing daemon */
+ send_sig_info(SIGIO, &lSigInfo, sDaemonTaskStruct);
+ }
+ else
+ /* Unlock the kernel */
+ spin_unlock_irqrestore(&sSpinLock, lFlags);
+
+ /* Indicate to the caller that everything is OK */
+ return 0;
+}
+
+/*************************************************************
+ * Function : tracer_switch_buffers()
+ * Description :
+ * Put the current write buffer to be read and reset put
+ * the old read buffer to be written to. Set the tracer
+ * variables in consequence.
+ * Parameters :
+ * pmTime, current time
+ * Return values :
+ * NONE
+ * Note :
+ * This should be called from within a spin_lock.
+ *************************************************************/
+void tracer_switch_buffers(struct timeval pmTime)
+{
+ char* lTempBuf; /* Temporary buffer pointer */
+ char* lTempBufEnd; /* Temporary buffer end pointer */
+ char* lInitWritPos; /* Initial write position */
+ uint8_t lDataSize; /* Size of tracing data */
+ uint8_t lEventID; /* Event ID of last event */
+ uint8_t lCPUID; /* CPUID of currently runing process */
+ uint32_t lSizeLost; /* Size delta between last event and end of buffer */
+ trace_time_delta lTimeDelta; /* The time elapsed between now and the last event */
+ trace_buffer_start lStartBufferEvent; /* Start of the new buffer event */
+
+ /* Remember initial write position */
+ lInitWritPos = sWritPos;
+
+ /* Write the end event at the write of the buffer */
+
+ /* Write the CPUID to the tracing buffer, if required */
+ if(sLogCPUID == TRUE)
+ {
+ lCPUID = smp_processor_id();
+ tracer_write_to_buffer(sWritPos,
+ &lCPUID,
+ sizeof(lCPUID));
+ }
+
+ /* Write event type to tracing buffer */
+ lEventID = TRACE_EV_BUFFER_END;
+ tracer_write_to_buffer(sWritPos,
+ &lEventID,
+ sizeof(lEventID));
+
+ /* Write event time delta to tracing buffer */
+ lTimeDelta = 0;
+ tracer_write_to_buffer(sWritPos,
+ &lTimeDelta,
+ sizeof(lTimeDelta));
+
+ /* Get size lost */
+ lSizeLost = sWritBufEnd - lInitWritPos;
+
+ /* Write size lost at the end of the buffer */
+ *((uint32_t*) (sWritBufEnd - sizeof(lSizeLost))) = lSizeLost;
+
+ /* Switch buffers */
+ lTempBuf = sReadBuf;
+ sReadBuf = sWritBuf;
+ sWritBuf = lTempBuf;
+
+ /* Set buffer ends */
+ lTempBufEnd = sReadBufEnd;
+ sReadBufEnd = sWritBufEnd;
+ sWritBufEnd = lTempBufEnd;
+
+ /* Set read limit */
+ sReadLimit = sReadBufEnd;
+
+ /* Set write limit */
+ sWritLimit = sWritBufEnd - TRACER_LAST_EVENT_SIZE;
+
+ /* Set write position */
+ sWritPos = sWritBuf;
+
+ /* Increment buffer ID */
+ sBufferID++;
+
+ /* Set the time of begining of this buffer */
+ sBufferStartTime = pmTime;
+
+ /* Write the start of buffer event */
+ lStartBufferEvent.ID = sBufferID;
+ lStartBufferEvent.Time = pmTime;
+
+ /* Write event type to tracing buffer */
+ lEventID = TRACE_EV_BUFFER_START;
+ tracer_write_to_buffer(sWritPos,
+ &lEventID,
+ sizeof(lEventID));
+
+ /* Write event time delta to tracing buffer */
+ lTimeDelta = 0;
+ tracer_write_to_buffer(sWritPos,
+ &lTimeDelta,
+ sizeof(lTimeDelta));
+
+ /* Write event structure */
+ tracer_write_to_buffer(sWritPos,
+ &lStartBufferEvent,
+ sizeof(lStartBufferEvent));
+
+ /* Compute the data size */
+ lDataSize = sizeof(lEventID)
+ + sizeof(lTimeDelta)
+ + sizeof(lStartBufferEvent)
+ + sizeof(lDataSize);
+
+ /* Write the length of the event description */
+ tracer_write_to_buffer(sWritPos,
+ &lDataSize,
+ sizeof(lDataSize));
+}
+
+/*************************************************************
+ * Function : tracer_ioctl()
+ * Description : "Ioctl" file op
+ * Parameters :
+ * pmInode, the inode associated with the device
+ * pmFile, file structure given to the acting process
+ * pmCmd, command given by the caller
+ * pmArg, arguments to the command
+ * Return values :
+ * >0, In case the caller requested the number of events
+ * lost.
+ * 0, Everything went OK
+ * -ENOSYS, no such command
+ * -EINVAL, tracer not properly configured
+ * -EBUSY, tracer can't be reconfigured while in operation
+ * -ENOMEM, no more memory
+ * Note :
+ * In the future, this function should check to make sure
+ * that it's the server that make thes ioctl.
+ *************************************************************/
+int tracer_ioctl(struct inode* pmInode,
+ struct file* pmFile,
+ unsigned int pmCmd,
+ unsigned long pmArg)
+{
+ trace_start lStartEvent; /* Event marking the begining of the trace */
+ unsigned long int lFlags; /* CPU flags for lock */
+ trace_buffer_start lStartBufferEvent; /* Start of the new buffer event */
+
+ /* If the tracer is started, the configuration can't be modified */
+ if((sTracerStarted == TRUE) && (pmCmd != TRACER_STOP) && (pmCmd != TRACER_DATA_COMITTED))
+ return -EBUSY;
+
+ /* Depending on the command executed */
+ switch(pmCmd)
+ {
+ /* Start the tracer */
+ case TRACER_START :
+ /* Check if the device has been properly set up */
+ if(((sUseSyscallEIPBounds == TRUE)
+ &&(sSyscallEIPDepthSet == TRUE))
+ ||((sUseSyscallEIPBounds == TRUE)
+ &&((sLowerEIPBoundSet != TRUE)
+ ||(sUpperEIPBoundSet != TRUE)))
+ ||((sTracingPID == TRUE)
+ &&(sTracingPGRP == TRUE)))
+ return -EINVAL;
+
+ /* Set the kernel-side trace configuration */
+ if(trace_set_config(trace,
+ sSyscallEIPDepthSet,
+ sUseSyscallEIPBounds,
+ sSyscallEIPDepth,
+ sLowerEIPBound,
+ sUpperEIPBound) < 0)
+ return -EINVAL;
+
+ /* Always log the start event and the buffer start event */
+ set_bit(TRACE_EV_BUFFER_START, &sTracedEvents);
+ set_bit(TRACE_EV_BUFFER_START, &sLogEventDetailsMask);
+ set_bit(TRACE_EV_START, &sTracedEvents);
+ set_bit(TRACE_EV_START, &sLogEventDetailsMask);
+
+ /* Get the time of start */
+ do_gettimeofday(&sBufferStartTime);
+
+ /* Set the event description */
+ lStartBufferEvent.ID = sBufferID;
+ lStartBufferEvent.Time = sBufferStartTime;
+
+ /* Set the event description */
+ lStartEvent.MagicNumber = TRACER_MAGIC_NUMBER;
+ lStartEvent.MajorVersion = TRACER_VERSION_MAJOR;
+ lStartEvent.MinorVersion = TRACER_VERSION_MINOR;
+ lStartEvent.BufferSize = sBufSize;
+ lStartEvent.EventMask = sTracedEvents;
+ lStartEvent.DetailsMask = sLogEventDetailsMask;
+ lStartEvent.LogCPUID = sLogCPUID;
+
+ /* We can start tracing */
+ sTracerStarted = TRUE;
+
+ /* Trace the buffer start event */
+ trace(TRACE_EV_BUFFER_START, &lStartBufferEvent);
+
+ /* Trace the start event */
+ trace(TRACE_EV_START, &lStartEvent);
+ break;
+
+ /* Stop the tracer */
+ case TRACER_STOP :
+ /* Stop tracing */
+ sTracerStarted = FALSE;
+
+ /* Switch the buffers to ensure that the end of the buffer mark is set (time isn't important) */
+ tracer_switch_buffers(sBufferStartTime);
+ break;
+
+ /* Set the tracer to the default configuration */
+ case TRACER_CONFIG_DEFAULT :
+ tracer_set_default_config();
+ break;
+
+ /* Set the memory buffers the daemon wants us to use */
+ case TRACER_CONFIG_MEMORY_BUFFERS :
+ /* Is the given size "reasonnable" */
+ if(pmArg < TRACER_MIN_BUF_SIZE)
+ return -EINVAL;
+
+ /* Is there an already allocated space greater or equal to the required space */
+ if((sTracBuf != NULL) && (sBufSize >= pmArg))
+ {
+#if 0
+ printk("Tracer: Reusing trace buffer \n");
+#endif
+
+ /* Set the read and write buffers */
+ sWritBuf = sTracBuf;
+ sReadBuf = sTracBuf + sBufSize;
+
+ /* Set end of buffers */
+ sWritBufEnd = sWritBuf + sBufSize;
+ sReadBufEnd = sReadBuf + sBufSize;
+
+ /* Set write position */
+ sWritPos = sWritBuf;
+
+ /* Set read limit */
+ sReadLimit = sReadBuf;
+
+ /* Set write limit */
+ sWritLimit = sWritBufEnd - TRACER_LAST_EVENT_SIZE;
+
+ /* Don't need to allocate anthing */
+ return 0;
+ }
+ else
+ {
+#if 0
+ printk("Tracer: Current trace buffer insufficient \n");
+ printk("Tracer: sBufSize = %d, pmArg = %d \n", sBufSize, (uint32_t) pmArg);
+#endif
+ /* Set the buffer's size */
+ return tracer_set_buffer_size(pmArg);
+ }
+ break;
+
+ /* Trace the given events */
+ case TRACER_CONFIG_EVENTS :
+ sTracedEvents = (trace_event_mask) pmArg;
+ break;
+
+ /* Record the details of the event, or not */
+ case TRACER_CONFIG_DETAILS :
+ sLogEventDetailsMask = (trace_event_mask) pmArg;
+ break;
+
+ /* Record the CPUID associated with the event */
+ case TRACER_CONFIG_CPUID :
+ sLogCPUID = TRUE;
+ break;
+
+ /* Trace only one process */
+ case TRACER_CONFIG_PID :
+ sTracingPID = TRUE;
+ sTracedPID = pmArg;
+ break;
+
+ /* Trace only the given process group */
+ case TRACER_CONFIG_PGRP :
+ sTracingPGRP = TRUE;
+ sTracedPGRP = pmArg;
+ break;
+
+ /* Trace the processes of a given group of users */
+ case TRACER_CONFIG_GID :
+ sTracingGID = TRUE;
+ sTracedGID = pmArg;
+ break;
+
+ /* Trace the processes of a given user */
+ case TRACER_CONFIG_UID :
+ sTracingUID = TRUE;
+ sTracedUID = pmArg;
+ break;
+
+ /* Set the call depth a which the EIP should be fetched on syscall */
+ case TRACER_CONFIG_SYSCALL_EIP_DEPTH :
+ sSyscallEIPDepthSet = TRUE;
+ sSyscallEIPDepth = pmArg;
+ break;
+
+ /* Set the lowerbound address from which EIP is recorded on syscall */
+ case TRACER_CONFIG_SYSCALL_EIP_LOWER :
+ /* We are using bounds for fetching the EIP where syscall was made */
+ sUseSyscallEIPBounds = TRUE;
+
+ /* Set the lower bound */
+ sLowerEIPBound = (void*) pmArg;
+
+ /* The lower bound has been set */
+ sLowerEIPBoundSet = TRUE;
+ break;
+
+ /* Set the upperbound address from which EIP is recorded on syscall */
+ case TRACER_CONFIG_SYSCALL_EIP_UPPER :
+ /* We are using bounds for fetching the EIP where syscall was made */
+ sUseSyscallEIPBounds = TRUE;
+
+ /* Set the lower bound */
+ sUpperEIPBound = (void*) pmArg;
+
+ /* The lower bound has been set */
+ sUpperEIPBoundSet = TRUE;
+ break;
+
+ /* The daemon has comitted the last trace */
+ case TRACER_DATA_COMITTED :
+#if 0
+ printk("Tracer: Data has been comitted \n");
+#endif
+
+ /* Safely set the signal sent flag to FALSE */
+ spin_lock_irqsave(&sSpinLock, lFlags);
+ sSignalSent = FALSE;
+ spin_unlock_irqrestore(&sSpinLock, lFlags);
+ break;
+
+ /* Get the number of events lost */
+ case TRACER_GET_EVENTS_LOST :
+ return sEventsLost;
+ break;
+
+ /* Unknow command */
+ default :
+ return -ENOSYS;
+ }
+
+ /* Everything went OK */
+ return 0;
+}
+
+/*************************************************************
+ * Function : tracer_mmap()
+ * Description : "Mmap" file op
+ * Parameters :
+ * pmInode, the inode associated with the device
+ * pmFile, file structure given to the acting process
+ * pmVmArea, Virtual memory area description structure
+ * Return values :
+ * 0 if ok
+ * -EAGAIN, when remap failed
+ ************************************************************/
+int tracer_mmap(struct file* pmFile,
+ struct vm_area_struct* pmVmArea)
+{
+ /* Remap trace buffer into the process's memory space */
+ if(remap_page_range(pmVmArea->vm_start,
+ virt_to_phys(sTracBuf),
+ pmVmArea->vm_end - pmVmArea->vm_start,
+ pmVmArea->vm_page_prot))
+ return -EAGAIN;
+
+#if 0
+ printk("Tracer: Trace buffer virtual address => 0x%08X \n", (uint32_t)sTracBuf);
+ printk("Tracer: Trace buffer physical address => 0x%08X \n", (uint32_t)virt_to_phys(sTracBuf));
+ printk("Tracer: Trace buffer virtual address in daemon space => 0x%08X \n", (uint32_t)pmVmArea->vm_start);
+ printk("Tracer: Trace buffer physical address in daemon space => 0x%08X \n", (uint32_t)virt_to_phys((void*)pmVmArea->vm_start));
+#endif
+
+ /* Tell the caller that the memory mapping worked OK */
+ return 0;
+}
+
+/*************************************************************
+ * Function : tracer_open()
+ * Description : "Open" file op
+ * Parameters :
+ * pmInode, the inode associated with the device
+ * pmFile, file structure given to the acting process
+ * Return values :
+ * 0, everything went OK
+ * -ENODEV, no such device.
+ * -EBUSY, the tracer is already in use.
+ ************************************************************/
+int tracer_open(struct inode* pmInode,
+ struct file* pmFile)
+{
+ int lDevMinor = MINOR(pmInode->i_rdev) & 0xf; /* Device minor number */
+
+ /* Don't allow more than one device of this type */
+ if(lDevMinor > 0)
+ return -ENODEV;
+
+ /* Don't allow the device to be open more than once */
+ if(sOpenCount)
+ return -EBUSY;
+
+ /* Fetch the task structure of the process that opened the device */
+ sDaemonTaskStruct = current;
+
+#if 0
+ /* DEBUG */
+ printk("<1>Process %d opened the tracing device \n", sDaemonTaskStruct->pid);
+#endif
+
+ /* Lock the device */
+ sOpenCount++;
+
+#ifdef MODULE
+ /* Increment module usage */
+ MOD_INC_USE_COUNT;
+#endif
+
+ /* Everything is OK */
+ return 0;
+}
+
+/*************************************************************
+ * Function : tracer_release()
+ * Description : "Release" file op
+ * Parameters :
+ * pmInode, the inode associated with the device
+ * pmFile, file structure given to the acting process
+ * Return values :
+ * 0, everything went OK
+ * Note :
+ * It is assumed that if the tracing daemon dies, exits
+ * or simply stops existing, the kernel or "someone" will
+ * call tracer_release. Otherwise, we're in trouble ...
+ *************************************************************/
+int tracer_release(struct inode* pmInode,
+ struct file* pmFile)
+{
+#if 0
+ /* Print out the number of bytes recorded */
+ printk("<1>Tracer: Recorded %d bytes \n", (sBufReadComplete * sBufSize) + sSizeReadIncomplete);
+#endif
+
+ /* Did we loose any events */
+ if(sEventsLost > 0)
+ printk("<1>Tracer: Lost %d events \n", sEventsLost);
+
+ /* Reset the daemon PID */
+ sDaemonTaskStruct = NULL;
+
+#if 0
+ /* Free any allocated buffers */
+ if(sTracBuf != NULL)
+ free_pages((uint32_t) sTracBuf, sBufSizeOrder);
+
+ /* Reset the read and write buffers */
+ sTracBuf = NULL;
+ sWritBuf = NULL;
+ sReadBuf = NULL;
+ sWritPos = NULL;
+ sReadLimit = NULL;
+ sWritLimit = NULL;
+#endif
+
+ /* Reset the tracer's configuration */
+ tracer_set_default_config();
+ sTracerStarted = FALSE;
+
+ /* Reset number of bytes recorded and number of events lost */
+ sBufReadComplete = 0;
+ sSizeReadIncomplete = 0;
+ sEventsLost = 0;
+
+ /* Reset signal sent */
+ sSignalSent = FALSE;
+
+ /* Unlock the device */
+ sOpenCount--;
+
+#ifdef MODULE
+ /* Decrement module usage */
+ MOD_DEC_USE_COUNT;
+#endif
+
+ /* Tell the caller that everything is OK */
+ return 0;
+}
+
+/*************************************************************
+ * Function : tracer_fsync()
+ * Description : "Fsync" file op
+ * Parameters :
+ * pmFile, file structure given to the acting process
+ * pmDEntry, dentry associated with file
+ * Return values :
+ * 0, everything went OK
+ * Note :
+ * We need to look the modifications of the values because
+ * they are read and written by trace().
+ * Sonia : ne m oublie pas, je suis toujours a toi....
+ *************************************************************/
+int tracer_fsync(struct file* pmFile,
+ struct dentry* pmDEntry)
+{
+ unsigned long int lFlags; /* CPU flags for lock */
+
+ /* Lock the kernel */
+ spin_lock_irqsave(&sSpinLock, lFlags);
+
+ /* Reset the write positions */
+ sWritPos = sWritBuf;
+
+ /* Reset read limit */
+ sReadLimit = sReadBuf;
+
+ /* Reset bytes recorded */
+ sBufReadComplete = 0;
+ sSizeReadIncomplete = 0;
+ sEventsLost = 0;
+
+ /* Reset signal sent */
+ sSignalSent = FALSE;
+
+ /* Unlock the kernel */
+ spin_unlock_irqrestore(&sSpinLock, lFlags);
+
+ /* Tell the caller that everything is OK */
+ return 0;
+}
+
+/*************************************************************
+ * Function : tracer_set_buffer_size()
+ * Description :
+ * Sets the size of the buffers containing the trace data.
+ * Parameters :
+ * pmSize, Size of buffers
+ * Return values :
+ * 0, Size setting went OK
+ * -ENOMEM, unable to get a hold of memory for tracer
+ *************************************************************/
+int tracer_set_buffer_size(int pmSize)
+{
+ int lNbPages; /* Number of pages to be allocated */
+ int lSizeAlloc; /* Size to be allocated */
+ uint32_t lStart; /* Buffering region start */
+ uint32_t lEnd; /* Buffering region end */
+
+ /* Set size to allocate (= pmSize * 2) */
+ lSizeAlloc = pmSize << 1;
+
+ /* Free the current buffers, if any */
+ if(sTracBuf != NULL)
+ {
+ /* Set the start and end of buffering region */
+ lStart = (uint32_t) sTracBuf;
+ lEnd = (uint32_t) sTracBuf + (sBufSize << 1);
+
+ /* Unset the reserved bit */
+ for(; lStart < lEnd; lStart += PAGE_SIZE)
+ clear_bit(PG_reserved, &(mem_map[MAP_NR(lStart)].flags));
+
+ /* Give back the pages */
+ free_pages((uint32_t) sTracBuf, sBufSizeOrder);
+ }
+
+ /* Compute the number of pages necessary for given size */
+ lNbPages = lSizeAlloc / PAGE_SIZE;
+ if((pmSize % PAGE_SIZE) != 0)
+ lNbPages += 1;
+
+ /* Compute the power of 2 that is above or equal to the number of pages needed */
+ sBufSizeOrder = 0;
+ while((lNbPages = lNbPages >> 1) != 0)
+ {
+ /* Is this an odd number greater than 2 */
+ if((lNbPages > 2) && ((lNbPages % 2) != 0))
+ lNbPages += 1;
+
+ /* Increment the order */
+ sBufSizeOrder += 1;
+ }
+
+#if 1
+ printk("Tracer: Buffer Size Order is %d \n", sBufSizeOrder);
+#endif
+
+ /* Allocate space for the tracing buffers */
+ sTracBuf = (char*) __get_free_pages(GFP_ATOMIC, sBufSizeOrder);
+ if(sTracBuf == NULL) return -ENOMEM;
+
+ /* Set the start and end of buffering region */
+ lStart = (uint32_t) sTracBuf;
+ lEnd = (uint32_t) sTracBuf + lSizeAlloc;
+
+ /* Make sure these pages are can be passed on to remap_page_range */
+ for(; lStart < lEnd; lStart += PAGE_SIZE)
+ set_bit(PG_reserved, &(mem_map[MAP_NR(lStart)].flags));
+
+ /* Remember the size set */
+ sBufSize = pmSize;
+
+ /* Set the read and write buffers */
+ sWritBuf = sTracBuf;
+ sReadBuf = sTracBuf + sBufSize;
+
+ /* Set end of buffers */
+ sWritBufEnd = sWritBuf + sBufSize;
+ sReadBufEnd = sReadBuf + sBufSize;
+
+ /* Set write position */
+ sWritPos = sWritBuf;
+
+ /* Set read limit */
+ sReadLimit = sReadBuf;
+
+ /* Set write limit */
+ sWritLimit = sWritBufEnd - TRACER_LAST_EVENT_SIZE;
+
+ /* All is OK */
+ return 0;
+}
+
+/*************************************************************
+ * Function : tracer_set_default_config()
+ * Description : Sets the tracer in its default config
+ * Parameters :
+ * NONE
+ * Return values :
+ * 0, everything went OK
+ * -ENOMEM, unable to get a hold of memory for tracer
+ *************************************************************/
+int tracer_set_default_config(void)
+{
+ int i; /* Generic index */
+ int lError = 0; /* Error, if any */
+
+ /* Initialize the event mask */
+ sTracedEvents = 0;
+
+ /* Initialize the event mask with all existing events with their details*/
+ for(i = 0; i <= TRACE_EV_MAX; i++)
+ {
+ set_bit(i, &sTracedEvents);
+ set_bit(i, &sLogEventDetailsMask);
+ }
+
+ /* Forget about the CPUID */
+ sLogCPUID = FALSE;
+
+ /* We aren't tracing any PID or GID in particular */
+ sTracingPID = FALSE;
+ sTracingPGRP = FALSE;
+ sTracingGID = FALSE;
+ sTracingUID = FALSE;
+
+ /* We aren't looking for a particular call depth */
+ sSyscallEIPDepthSet = FALSE;
+
+ /* We aren't going to place bounds on syscall EIP fetching */
+ sUseSyscallEIPBounds = FALSE;
+ sLowerEIPBoundSet = FALSE;
+ sUpperEIPBoundSet = FALSE;
+
+ /* Set the kernel trace configuration to it's basics */
+ trace_set_config(trace,
+ sSyscallEIPDepthSet,
+ sUseSyscallEIPBounds,
+ 0,
+ 0,
+ 0);
+
+ /* Return the error code */
+ return lError;
+}
+
+/**************************************************************
+ * Function : tracer_init()
+ * Description : Tracer initialization function.
+ * Parameters :
+ * NONE
+ * Return values :
+ * 0, everything went OK
+ * -ENOMEM, unable to get a hold of memory for tracer
+ **************************************************************/
+int tracer_init(void)
+{
+ int lError = 0; /* Error, if any */
+
+ /* Initialize configuration */
+ if((lError = tracer_set_default_config()) < 0)
+ return lError;
+
+ /* Initialize open count */
+ sOpenCount = 0;
+
+ /* Initialize tracer lock */
+ sTracLock = 0;
+
+ /* Initialize signal sent */
+ sSignalSent = FALSE;
+
+ /* Initialize bytes read and events lost */
+ sBufReadComplete = 0;
+ sSizeReadIncomplete = 0;
+ sEventsLost = 0;
+
+ /* Initialize buffer ID */
+ sBufferID = 0;
+
+ /* Initialize tracing daemon task structure */
+ sDaemonTaskStruct = NULL;
+
+ /* Initialize spin lock */
+ sSpinLock = SPIN_LOCK_UNLOCKED;
+
+ /* Register the tracer as a char device */
+ sMajorNumber = register_chrdev(0, TRACER_NAME, &sTracerFileOps);
+
+ /* Register the tracer with the kernel */
+ register_tracer(trace);
+
+ /* Let the user know about it */
+#if 1
+ printk("<1>Tracer: Initialization complete \n");
+#endif
+
+ /* Return error code */
+ return lError;
+}
+
+/* Is this loaded as a module */
+#ifdef MODULE
+/**************************************************************
+ * Function : cleanup_module()
+ * Description : Cleanup of the tracer.
+ * Parameters : NONE
+ * Return values : NONE
+ * Note : The order of the unregesterings is important. First,
+ * rule out any possibility of getting more trace
+ * data. Second, rule out any possibility of being read
+ * by the tracing daemon. Last, free the tracing
+ * buffer.
+ **************************************************************/
+void cleanup_module(void)
+{
+ uint32_t lStart; /* Buffering region start */
+ uint32_t lEnd; /* Buffering region end */
+
+ /* Unregister the tracer from the kernel */
+ unregister_tracer(trace);
+
+ /* Unregister the tracer from being a char device */
+ unregister_chrdev(sMajorNumber, TRACER_NAME);
+
+ /* Free the current buffers, if any */
+ if(sTracBuf != NULL)
+ {
+ /* Set the start and end of buffering region */
+ lStart = (uint32_t) sTracBuf;
+ lEnd = (uint32_t) sTracBuf + (sBufSize << 1);
+
+ /* Unset the reserved bit */
+ for(; lStart < lEnd; lStart += PAGE_SIZE)
+ clear_bit(PG_reserved, &(mem_map[MAP_NR(lStart)].flags));
+
+ /* Give back the pages */
+ free_pages((uint32_t) sTracBuf, sBufSizeOrder);
+ }
+ sTracBuf = NULL;
+}
+
+/**************************************************************
+ * Function : init_module()
+ * Description : Initialization of the tracer.
+ * Parameters :
+ * NONE
+ * Return values :
+ * 0, everything went OK
+ * -ENOMEM, unable to get a hold of memory for tracer
+ **************************************************************/
+int init_module(void)
+#else
+/**************************************************************
+ * Function : tracer_setup()
+ * Description : Trace setup function.
+ * Parameters :
+ * NONE
+ * Return values :
+ * 0, everything went OK
+ * -ENOMEM, unable to get a hold of memory for tracer
+ **************************************************************/
+__initfunc(int tracer_setup(void))
+#endif /* MODULE */
+{
+ /* Initialize the tracer and return status */
+ return tracer_init();
+}
+
diff -urN linux/drivers/trace/tracer.h linux-2.2.14/drivers/trace/tracer.h
--- linux/drivers/trace/tracer.h Wed Dec 31 19:00:00 1969
+++ linux-2.2.14/drivers/trace/tracer.h Mon Mar 27 02:19:54 2000
@@ -0,0 +1,124 @@
+/*
+ * drivers/trace/tracer.h
+ *
+ * Copyright (C) 1999, Karim Yaghmour
+ *
+ * This contains the necessary definitions the system tracer
+ */
+
+#ifndef _TRACER_H
+#define _TRACER_H
+
+/* Logic values */
+#define FALSE 0
+#define TRUE 1
+
+/* Tracer properties */
+#define TRACER_NAME "tracer" /* Name of the device as seen in /proc/devices */
+
+/* Tracer buffer information */
+#define TRACER_DEFAULT_BUF_SIZE 50000 /* Default size of tracing buffer */
+#define TRACER_MIN_BUF_SIZE 1000 /* Minimum size of tracing buffer */
+#define TRACER_MAX_BUF_SIZE 500000 /* Maximum size of tracing buffer */
+
+/* Local definitions */
+typedef uint32_t trace_time_delta; /* The type used to start the time delta between events */
+typedef uint32_t trace_event_mask; /* The event mask type */
+
+/* Number of bytes set aside for last event */
+#define TRACER_LAST_EVENT_SIZE (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(trace_time_delta) + sizeof(uint32_t))
+
+/* The information logged when the tracing is started */
+#define TRACER_MAGIC_NUMBER 0x000D6B7ED /* That day marks an important historical event ... */
+#define TRACER_VERSION_MAJOR 1 /* Major version number */
+#define TRACER_VERSION_MINOR 3 /* Minor version number */
+typedef struct _trace_start
+{
+ uint32_t MagicNumber; /* Magic number to identify a trace */
+ uint8_t MajorVersion; /* Major version of trace */
+ uint8_t MinorVersion; /* Minor version of trace */
+ uint32_t BufferSize; /* Size of buffers */
+ trace_event_mask EventMask; /* The event mask */
+ trace_event_mask DetailsMask; /* Are the event details logged */
+ uint8_t LogCPUID; /* Is the CPUID logged */
+} trace_start;
+
+/* Start and end of trace buffer information */
+typedef struct _trace_buffer_start
+{
+ struct timeval Time; /* Time stamp of this buffer */
+ uint32_t ID; /* Unique buffer ID */
+} trace_buffer_start;
+
+/* Custom declared events */
+typedef struct _trace_new_event
+{
+ uint16_t ID; /* Unique event ID for new event */
+ uint32_t DescriptSize; /* Size of the description of the event */
+ char* Description; /* Description of new event */
+} trace_new_event;
+typedef struct _trace_custom
+{
+ uint16_t ID; /* Event ID */
+ uint32_t DataSize; /* Size of data recorded by event */
+ void* Data; /* Data recorded by event */
+} trace_custom;
+
+
+/* The configurations possible */
+#define TRACER_START 0 /* Start tracing events using the current configuration */
+#define TRACER_STOP 1 /* Stop tracing */
+#define TRACER_CONFIG_DEFAULT 2 /* Set the tracer to the default configuration */
+#define TRACER_CONFIG_MEMORY_BUFFERS 3 /* Set the memory buffers the daemon wants us to use */
+#define TRACER_CONFIG_EVENTS 4 /* Trace the given events */
+#define TRACER_CONFIG_DETAILS 5 /* Record the details of the event, or not */
+#define TRACER_CONFIG_CPUID 6 /* Record the CPUID associated with the event */
+#define TRACER_CONFIG_PID 7 /* Trace only one process */
+#define TRACER_CONFIG_PGRP 8 /* Trace only the given process group */
+#define TRACER_CONFIG_GID 9 /* Trace the processes of a given group of users */
+#define TRACER_CONFIG_UID 10 /* Trace the processes of a given user */
+#define TRACER_CONFIG_SYSCALL_EIP_DEPTH 11 /* Set the call depth at which the EIP should be fetched on syscall */
+#define TRACER_CONFIG_SYSCALL_EIP_LOWER 12 /* Set the lowerbound address from which EIP is recorded on syscall */
+#define TRACER_CONFIG_SYSCALL_EIP_UPPER 13 /* Set the upperbound address from which EIP is recorded on syscall */
+#define TRACER_DATA_COMITTED 14 /* The daemon has comitted the last trace */
+#define TRACER_GET_EVENTS_LOST 15 /* Get the number of events lost */
+
+/* Function prototypes */
+int trace
+ (uint8_t,
+ void*);
+void tracer_switch_buffers
+ (struct timeval);
+int tracer_ioctl
+ (struct inode*,
+ struct file*,
+ unsigned int,
+ unsigned long);
+int tracer_mmap
+ (struct file*,
+ struct vm_area_struct*);
+int tracer_open
+ (struct inode*,
+ struct file*);
+int tracer_release
+ (struct inode*,
+ struct file*);
+int tracer_fsync
+ (struct file*,
+ struct dentry*);
+#ifdef MODULE
+int init_module
+ (void);
+void cleanup_module
+ (void);
+#else
+int tracer_setup
+ (void);
+#endif
+int tracer_set_buffer_size
+ (int);
+int tracer_set_default_config
+ (void);
+int tracer_init
+ (void);
+#endif /* _TRACER_H */
diff -urN linux/fs/buffer.c linux-2.2.14/fs/buffer.c
--- linux/fs/buffer.c Tue Jan 4 13:12:22 2000
+++ linux-2.2.14/fs/buffer.c Mon Mar 27 02:49:47 2000
@@ -40,6 +40,8 @@
 #include <linux/init.h>
 #include <linux/quotaops.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
@@ -140,12 +142,14 @@
         add_wait_queue(&bh->b_wait, &wait);
 repeat:
         tsk->state = TASK_UNINTERRUPTIBLE;
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_BUF_WAIT_START, 0, 0, NULL);
         run_task_queue(&tq_disk);
         if (buffer_locked(bh)) {
                 schedule();
                 goto repeat;
         }
         tsk->state = TASK_RUNNING;
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_BUF_WAIT_END, 0, 0, NULL);
         remove_wait_queue(&bh->b_wait, &wait);
         bh->b_count--;
 }
diff -urN linux/fs/exec.c linux-2.2.14/fs/exec.c
--- linux/fs/exec.c Tue Oct 26 20:53:42 1999
+++ linux-2.2.14/fs/exec.c Mon Mar 27 02:50:46 2000
@@ -32,6 +32,8 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
@@ -817,6 +819,11 @@
         retval = PTR_ERR(dentry);
         if (IS_ERR(dentry))
                 return retval;
+
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_EXEC,
+ 0,
+ dentry->d_name.len,
+ dentry->d_name.name);
 
         bprm.dentry = dentry;
         bprm.filename = filename;
diff -urN linux/fs/ioctl.c linux-2.2.14/fs/ioctl.c
--- linux/fs/ioctl.c Wed Aug 25 20:29:49 1999
+++ linux-2.2.14/fs/ioctl.c Mon Mar 27 02:51:42 2000
@@ -8,6 +8,8 @@
 #include <linux/smp_lock.h>
 #include <linux/file.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
@@ -52,6 +54,10 @@
         if (!filp)
                 goto out;
         error = 0;
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_IOCTL,
+ fd,
+ cmd,
+ NULL);
         switch (cmd) {
                 case FIOCLEX:
                         FD_SET(fd, current->files->close_on_exec);
diff -urN linux/fs/open.c linux-2.2.14/fs/open.c
--- linux/fs/open.c Tue Jan 4 13:12:23 2000
+++ linux-2.2.14/fs/open.c Mon Mar 27 02:53:18 2000
@@ -10,6 +10,8 @@
 #include <linux/smp_lock.h>
 #include <linux/quotaops.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 asmlinkage int sys_statfs(const char * path, struct statfs * buf)
@@ -770,6 +772,10 @@
                         error = PTR_ERR(f);
                         if (IS_ERR(f))
                                 goto out_error;
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_OPEN,
+ fd,
+ f->f_dentry->d_name.len,
+ f->f_dentry->d_name.name);
                         fd_install(fd, f);
                 }
 out:
@@ -850,6 +856,10 @@
         filp = fcheck(fd);
         if (filp) {
                 struct files_struct * files = current->files;
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_CLOSE,
+ fd,
+ 0,
+ NULL);
                 files->fd[fd] = NULL;
                 put_unused_fd(fd);
                 FD_CLR(fd, files->close_on_exec);
diff -urN linux/fs/read_write.c linux-2.2.14/fs/read_write.c
--- linux/fs/read_write.c Tue Jan 4 13:12:23 2000
+++ linux-2.2.14/fs/read_write.c Mon Mar 27 02:57:30 2000
@@ -11,6 +11,8 @@
 #include <linux/uio.h>
 #include <linux/smp_lock.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 static loff_t default_llseek(struct file *file, loff_t offset, int origin)
@@ -65,6 +67,10 @@
         retval = -EINVAL;
         if (origin <= 2)
                 retval = llseek(file, offset, origin);
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SEEK,
+ fd,
+ offset,
+ NULL);
 out_putf:
         fput(file);
 bad:
@@ -98,6 +104,10 @@
 
         offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
                         origin);
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SEEK,
+ fd,
+ offset,
+ NULL);
 
         retval = (int)offset;
         if (offset >= 0) {
@@ -134,6 +144,10 @@
         ret = -EINVAL;
         if (!file->f_op || !(read = file->f_op->read))
                 goto out;
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ,
+ fd,
+ count,
+ NULL);
         ret = read(file, buf, count, &file->f_pos);
 out:
         fput(file);
@@ -166,6 +180,10 @@
         if (!file->f_op || !(write = file->f_op->write))
                 goto out;
 
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE,
+ fd,
+ count,
+ NULL);
         down(&inode->i_sem);
         ret = write(file, buf, count, &file->f_pos);
         up(&inode->i_sem);
@@ -282,6 +300,10 @@
         file = fget(fd);
         if (!file)
                 goto bad_file;
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ,
+ fd,
+ count,
+ NULL);
         if (file->f_op && file->f_op->read && (file->f_mode & FMODE_READ))
                 ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
         fput(file);
@@ -303,6 +325,10 @@
         file = fget(fd);
         if (!file)
                 goto bad_file;
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE,
+ fd,
+ count,
+ NULL);
         if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) {
                 down(&file->f_dentry->d_inode->i_sem);
                 ret = do_readv_writev(VERIFY_READ, file, vector, count);
@@ -343,6 +369,10 @@
                 goto out;
         if (pos < 0)
                 goto out;
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ,
+ fd,
+ count,
+ NULL);
         ret = read(file, buf, count, &pos);
 out:
         fput(file);
@@ -376,6 +406,10 @@
         if (pos < 0)
                 goto out;
 
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE,
+ fd,
+ count,
+ NULL);
         down(&file->f_dentry->d_inode->i_sem);
         ret = write(file, buf, count, &pos);
         up(&file->f_dentry->d_inode->i_sem);
diff -urN linux/fs/select.c linux-2.2.14/fs/select.c
--- linux/fs/select.c Wed Aug 25 20:29:49 1999
+++ linux-2.2.14/fs/select.c Mon Mar 27 02:59:33 2000
@@ -15,6 +15,8 @@
 #include <linux/poll.h>
 #include <linux/file.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 #define ROUND_UP(x,y) (((x)+(y)-1)/(y))
@@ -190,6 +192,10 @@
                         file = fcheck(i);
                         mask = POLLNVAL;
                         if (file) {
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SELECT,
+ i /* The fd*/,
+ __timeout,
+ NULL);
                                 mask = DEFAULT_POLLMASK;
                                 if (file->f_op && file->f_op->poll)
                                         mask = file->f_op->poll(file, wait);
@@ -362,6 +368,10 @@
                                 struct file * file = fcheck(fd);
                                 mask = POLLNVAL;
                                 if (file != NULL) {
+ TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_POLL,
+ fd,
+ timeout,
+ NULL);
                                         mask = DEFAULT_POLLMASK;
                                         if (file->f_op && file->f_op->poll)
                                                 mask = file->f_op->poll(file, wait);
diff -urN linux/include/linux/trace.h linux-2.2.14/include/linux/trace.h
--- linux/include/linux/trace.h Wed Dec 31 19:00:00 1969
+++ linux-2.2.14/include/linux/trace.h Mon Mar 27 03:51:00 2000
@@ -0,0 +1,323 @@
+/*
+ * linux/include/linux/trace.h
+ *
+ * Copyright (C) 1999, Karim Yaghmour
+ *
+ * This contains the necessary definitions for tracing the
+ * the system.
+ */
+
+#ifndef _LINUX_TRACE_H
+#define _LINUX_TRACE_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+/* Is kernel tracing enabled */
+#if defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE)
+/* The prototype of the tracer call (EventID, *EventStruct) */
+typedef int (*tracer_call) (uint8_t, void*);
+
+/* This structure contains all the information needed to be known
+ about the tracing module. */
+struct tracer
+{
+ /* The tracing routine itself */
+ tracer_call trace;
+
+ /* Fetch of eip origin of syscall */
+ int fetch_syscall_eip_use_depth; /* Use the given depth */
+ int fetch_syscall_eip_use_bounds; /* Find eip in bounds */
+ int syscall_eip_depth; /* Call depth at which eip is fetched */
+ void* syscall_lower_eip_bound; /* Lower eip bound */
+ void* syscall_upper_eip_bound; /* Higher eip bound */
+};
+
+/* The functions to the tracer management code */
+int register_tracer
+ (tracer_call /* The tracer function */);
+int unregister_tracer
+ (tracer_call /* The tracer function */);
+int trace_set_config
+ (tracer_call /* The tracer function */,
+ int /* Use depth to fetch eip */,
+ int /* Use bounds to fetch eip */,
+ int /* Detph to fetch eip */,
+ void* /* Lower bound eip address */,
+ void* /* Upper bound eip address */);
+int trace_get_config
+ (int* /* Use depth to fetch eip */,
+ int* /* Use bounds to fetch eip */,
+ int* /* Detph to fetch eip */,
+ void** /* Lower bound eip address */,
+ void** /* Upper bound eip address */);
+int trace_event
+ (uint8_t /* Event ID (as defined in this header file) */,
+ void* /* Structure describing the event */);
+
+/* Generic macros */
+#define TRACE_EVENT(ID, DATA) trace_event(ID, DATA)
+
+/* Traced events */
+#define TRACE_EV_START 0 /* This is to mark the trace's start */
+#define TRACE_EV_SYSCALL_ENTRY 1 /* Entry in a given system call */
+#define TRACE_EV_SYSCALL_EXIT 2 /* Exit from a given system call */
+#define TRACE_EV_TRAP_ENTRY 3 /* Entry in a trap */
+#define TRACE_EV_TRAP_EXIT 4 /* Exit from a trap */
+#define TRACE_EV_IRQ_ENTRY 5 /* Entry in an irq */
+#define TRACE_EV_IRQ_EXIT 6 /* Exit from an irq */
+#define TRACE_EV_SCHEDCHANGE 7 /* Scheduling change */
+#define TRACE_EV_KERNEL_TIMER 8 /* The kernel timer routine has been called */
+#define TRACE_EV_BOTTOM_HALF 9 /* Going to run a bottom half */
+#define TRACE_EV_PROCESS 10 /* Hit key part of process management */
+#define TRACE_EV_FILE_SYSTEM 11 /* Hit key part of file system */
+#define TRACE_EV_TIMER 12 /* Hit key part of timer management */
+#define TRACE_EV_MEMORY 13 /* Hit key part of memory management */
+#define TRACE_EV_SOCKET 14 /* Hit key part of socket communication */
+#define TRACE_EV_IPC 15 /* Hit key part of System V IPC */
+#define TRACE_EV_NETWORK 16 /* Hit key part of network communication */
+
+#define TRACE_EV_BUFFER_START 17 /* Mark the begining of a trace buffer */
+#define TRACE_EV_BUFFER_END 18 /* Mark the ending of a trace buffer */
+#define TRACE_EV_NEW_EVENT 19 /* New event type */
+#define TRACE_EV_CUSTOM 20 /* Custom event */
+
+/* Number of traced events */
+#define TRACE_EV_MAX TRACE_EV_CUSTOM
+
+/* Structures and macros for events */
+/* TRACE_SYSCALL_ENTRY */
+typedef struct _trace_syscall_entry
+{
+ uint8_t syscall_id; /* Syscall entry number in entry.S */
+ uint32_t address; /* Address from which call was made */
+} trace_syscall_entry;
+
+/* TRACE_TRAP_ENTRY */
+typedef struct _trace_trap_entry
+{
+ uint8_t trap_id; /* Trap number */
+ uint32_t address; /* Address where trap occured */
+} trace_trap_entry;
+#define TRACE_TRAP_ENTRY(ID, EIP) \
+ do \
+ {\
+ trace_trap_entry trap_event;\
+ trap_event.trap_id = ID;\
+ trap_event.address = EIP;\
+ trace_event(TRACE_EV_TRAP_ENTRY, &trap_event);\
+ } while(0);
+
+/* TRACE_IRQ_ENTRY */
+typedef struct _trace_irq_entry
+{
+ uint8_t irq_id : 6; /* IRQ number 2^6 = 64 */
+ uint8_t unused : 1; /* This isn't used for now */
+ uint8_t kernel : 1; /* Are we executing kernel code */
+} trace_irq_entry;
+#define TRACE_IRQ_ENTRY(ID, KERNEL) \
+ do \
+ {\
+ trace_irq_entry irq_entry;\
+ irq_entry.irq_id = ID;\
+ irq_entry.kernel = KERNEL;\
+ trace_event(TRACE_EV_IRQ_ENTRY, &irq_entry);\
+ } while(0);
+
+/* TRACE_SCHEDCHANGE */
+typedef struct _trace_schedchange
+{
+ pid_t out; /* Outgoing process */
+ pid_t in; /* Incoming process */
+ uint32_t out_state; /* Outgoing process' state */
+} trace_schedchange;
+#define TRACE_SCHEDCHANGE(OUT, IN, OUT_STATE) \
+ do \
+ {\
+ trace_schedchange sched_event;\
+ sched_event.out = OUT;\
+ sched_event.in = IN;\
+ sched_event.out_state = OUT_STATE; \
+ trace_event(TRACE_EV_SCHEDCHANGE, &sched_event);\
+ } while(0);
+
+/* TRACE_BOTTOM_HALF */
+#define trace_bottom_half uint8_t /* ID of bottom half */
+#define TRACE_BOTTOM_HALF(ID) \
+ do \
+ {\
+ trace_bottom_half bh_event = ID;\
+ trace_event(TRACE_EV_BOTTOM_HALF, &bh_event);\
+ } while(0);
+
+/* TRACE_PROCESS */
+#define TRACE_EV_PROCESS_KTHREAD 1 /* Creation of a kernel thread */
+#define TRACE_EV_PROCESS_FORK 2 /* A fork or clone occured */
+#define TRACE_EV_PROCESS_EXIT 3 /* An exit occured */
+#define TRACE_EV_PROCESS_WAIT 4 /* A wait occured */
+#define TRACE_EV_PROCESS_SIGNAL 5 /* A signal has been sent */
+#define TRACE_EV_PROCESS_WAKEUP 6 /* Wake up a process */
+typedef struct _trace_process
+{
+ uint8_t event_sub_id; /* Process event ID */
+ uint32_t event_data1; /* Data associated with event */
+ uint32_t event_data2;
+} trace_process;
+#define TRACE_PROCESS(ID, DATA1, DATA2) \
+ do \
+ {\
+ trace_process proc_event;\
+ proc_event.event_sub_id = ID;\
+ proc_event.event_data1 = DATA1;\
+ proc_event.event_data2 = DATA2;\
+ trace_event(TRACE_EV_PROCESS, &proc_event);\
+ } while(0);
+
+/* TRACE_FILE_SYSTEM */
+#define TRACE_EV_FILE_SYSTEM_BUF_WAIT_START 1 /* Starting to wait for a data buffer */
+#define TRACE_EV_FILE_SYSTEM_BUF_WAIT_END 2 /* End to wait for a data buffer */
+#define TRACE_EV_FILE_SYSTEM_EXEC 3 /* An exec occured */
+#define TRACE_EV_FILE_SYSTEM_OPEN 4 /* An open occured */
+#define TRACE_EV_FILE_SYSTEM_CLOSE 5 /* A close occured */
+#define TRACE_EV_FILE_SYSTEM_READ 6 /* A read occured */
+#define TRACE_EV_FILE_SYSTEM_WRITE 7 /* A write occured */
+#define TRACE_EV_FILE_SYSTEM_SEEK 8 /* A seek occured */
+#define TRACE_EV_FILE_SYSTEM_IOCTL 9 /* An ioctl occured */
+#define TRACE_EV_FILE_SYSTEM_SELECT 10 /* A select occured */
+#define TRACE_EV_FILE_SYSTEM_POLL 11 /* A poll occured */
+typedef struct _trace_file_system
+{
+ uint8_t event_sub_id; /* File system event ID */
+ uint32_t event_data1; /* Event data */
+ uint32_t event_data2; /* Event data 2 */
+ char* file_name; /* Name of file operated on */
+} trace_file_system;
+#define TRACE_FILE_SYSTEM(ID, DATA1, DATA2, FILE_NAME) \
+ do \
+ {\
+ trace_file_system fs_event;\
+ fs_event.event_sub_id = ID;\
+ fs_event.event_data1 = DATA1;\
+ fs_event.event_data2 = DATA2;\
+ fs_event.file_name = (char*)FILE_NAME;\
+ trace_event(TRACE_EV_FILE_SYSTEM, &fs_event);\
+ } while(0);
+
+/* TRACE_TIMER */
+#define TRACE_EV_TIMER_EXPIRED 1 /* Timer expired */
+#define TRACE_EV_TIMER_SETITIMER 2 /* Setting itimer occurred */
+#define TRACE_EV_TIMER_SETTIMEOUT 3 /* Setting sched timeout occurred */
+typedef struct _trace_timer
+{
+ uint8_t event_sub_id; /* Timer event ID */
+ uint8_t event_sdata; /* Short data */
+ uint32_t event_data1; /* Data associated with event */
+ uint32_t event_data2;
+} trace_timer;
+#define TRACE_TIMER(ID, SDATA, DATA1, DATA2) \
+ do \
+ {\
+ trace_timer timer_event;\
+ timer_event.event_sub_id = ID;\
+ timer_event.event_sdata = SDATA;\
+ timer_event.event_data1 = DATA1;\
+ timer_event.event_data2 = DATA2;\
+ trace_event(TRACE_EV_TIMER, &timer_event);\
+ } while(0);
+
+/* TRACE_MEMORY */
+#define TRACE_EV_MEMORY_PAGE_ALLOC 1 /* Allocating pages */
+#define TRACE_EV_MEMORY_PAGE_FREE 2 /* Freing pages */
+#define TRACE_EV_MEMORY_SWAP_IN 3 /* Swaping pages in */
+#define TRACE_EV_MEMORY_SWAP_OUT 4 /* Swaping pages out */
+#define TRACE_EV_MEMORY_PAGE_WAIT_START 5 /* Start to wait for page */
+#define TRACE_EV_MEMORY_PAGE_WAIT_END 6 /* End to wait for page */
+typedef struct _trace_memory
+{
+ uint8_t event_sub_id; /* Memory event ID */
+ unsigned long event_data; /* Data associated with event */
+} trace_memory;
+#define TRACE_MEMORY(ID, DATA) \
+ do \
+ {\
+ trace_memory memory_event;\
+ memory_event.event_sub_id = ID;\
+ memory_event.event_data = DATA;\
+ trace_event(TRACE_EV_MEMORY, &memory_event);\
+ } while(0);
+
+/* TRACE_SOCKET */
+#define TRACE_EV_SOCKET_CALL 1 /* A socket call occured */
+#define TRACE_EV_SOCKET_CREATE 2 /* A socket has been created */
+#define TRACE_EV_SOCKET_SEND 3 /* Data was sent to a socket */
+#define TRACE_EV_SOCKET_RECEIVE 4 /* Data was read from a socket */
+typedef struct _trace_socket
+{
+ uint8_t event_sub_id; /* Socket event ID */
+ uint32_t event_data1; /* Data associated with event */
+ uint32_t event_data2; /* Data associated with event */
+} trace_socket;
+#define TRACE_SOCKET(ID, DATA1, DATA2) \
+ do \
+ {\
+ trace_socket socket_event;\
+ socket_event.event_sub_id = ID;\
+ socket_event.event_data1 = DATA1;\
+ socket_event.event_data2 = DATA2;\
+ trace_event(TRACE_EV_SOCKET, &socket_event);\
+ } while(0);
+
+/* TRACE_IPC */
+#define TRACE_EV_IPC_CALL 1 /* A System V IPC call occured */
+#define TRACE_EV_IPC_MSG_CREATE 2 /* A message queue has been created */
+#define TRACE_EV_IPC_SEM_CREATE 3 /* A semaphore was created */
+#define TRACE_EV_IPC_SHM_CREATE 4 /* A shared memory segment has been created */
+typedef struct _trace_ipc
+{
+ uint8_t event_sub_id; /* IPC event ID */
+ uint32_t event_data1; /* Data associated with event */
+ uint32_t event_data2; /* Data associated with event */
+} trace_ipc;
+#define TRACE_IPC(ID, DATA1, DATA2) \
+ do \
+ {\
+ trace_ipc ipc_event;\
+ ipc_event.event_sub_id = ID;\
+ ipc_event.event_data1 = DATA1;\
+ ipc_event.event_data2 = DATA2;\
+ trace_event(TRACE_EV_IPC, &ipc_event);\
+ } while(0);
+
+/* TRACE_NETWORK */
+#define TRACE_EV_NETWORK_PACKET_IN 1 /* A packet came in */
+#define TRACE_EV_NETWORK_PACKET_OUT 2 /* A packet was sent */
+typedef struct _trace_network
+{
+ uint8_t event_sub_id; /* Network event ID */
+ uint32_t event_data; /* Event data */
+} trace_network;
+#define TRACE_NETWORK(ID, DATA) \
+ do \
+ {\
+ trace_network net_event;\
+ net_event.event_sub_id = ID;\
+ net_event.event_data = DATA;\
+ trace_event(TRACE_EV_NETWORK, &net_event);\
+ } while(0);
+
+#else /* Kernel is configured without tracing */
+#define TRACE_EVENT(ID, DATA)
+#define TRACE_TRAP_ENTRY(ID, EIP)
+#define TRACE_IRQ_ENTRY(ID, KERNEL)
+#define TRACE_SCHEDCHANGE(OUT, IN, OUT_STATE)
+#define TRACE_BOTTOM_HALF(ID)
+#define TRACE_PROCESS(ID, DATA1, DATA2)
+#define TRACE_FILE_SYSTEM(ID, DATA1, DATA2, FILE_NAME)
+#define TRACE_TIMER(ID, SDATA, DATA1, DATA2)
+#define TRACE_MEMORY(ID, DATA)
+#define TRACE_SOCKET(ID, DATA1, DATA2)
+#define TRACE_IPC(ID, DATA1, DATA2)
+#define TRACE_NETWORK(ID, DATA)
+#endif /* defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE) */
+
+#endif /* _LINUX_TRACE_H */
diff -urN linux/init/main.c linux-2.2.14/init/main.c
--- linux/init/main.c Tue Jan 4 13:12:25 2000
+++ linux-2.2.14/init/main.c Mon Mar 27 03:02:27 2000
@@ -22,6 +22,7 @@
 #include <linux/smp_lock.h>
 #include <linux/blk.h>
 #include <linux/hdreg.h>
+#include <linux/trace.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -374,6 +375,10 @@
 extern void md_setup(char *str,int *ints) __init;
 #endif
 
+#ifdef CONFIG_TRACE
+extern void tracer_setup(void);
+#endif
+
 /*
  * Boot command-line arguments
  */
@@ -1408,6 +1413,11 @@
         real_root_mountflags = root_mountflags;
         if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY;
         else mount_initrd =0;
+#endif
+
+#ifdef CONFIG_TRACE
+ /* Setup the tracer */
+ tracer_setup();
 #endif
 
         /* Set up devices .. */
diff -urN linux/ipc/msg.c linux-2.2.14/ipc/msg.c
--- linux/ipc/msg.c Tue Jan 4 13:12:25 2000
+++ linux-2.2.14/ipc/msg.c Mon Mar 27 03:03:46 2000
@@ -16,6 +16,8 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
@@ -333,6 +335,7 @@
                         ret = (unsigned int) msq->msg_perm.seq * MSGMNI + id;
         }
         unlock_kernel();
+ TRACE_IPC(TRACE_EV_IPC_MSG_CREATE, ret, msgflg);
         return ret;
 }
 
diff -urN linux/ipc/sem.c linux-2.2.14/ipc/sem.c
--- linux/ipc/sem.c Tue Jan 4 13:12:25 2000
+++ linux-2.2.14/ipc/sem.c Mon Mar 27 03:04:51 2000
@@ -54,6 +54,8 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 extern int ipcperms (struct ipc_perm *ipcp, short semflg);
@@ -171,6 +173,7 @@
         }
 out:
         unlock_kernel();
+ TRACE_IPC(TRACE_EV_IPC_SEM_CREATE, err, semflg);
         return err;
 }
 
diff -urN linux/ipc/shm.c linux-2.2.14/ipc/shm.c
--- linux/ipc/shm.c Tue Jan 4 13:12:25 2000
+++ linux-2.2.14/ipc/shm.c Mon Mar 27 03:05:49 2000
@@ -13,6 +13,8 @@
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
@@ -163,6 +165,7 @@
         }
         unlock_kernel();
         up(&current->mm->mmap_sem);
+ TRACE_IPC(TRACE_EV_IPC_SHM_CREATE, err, shmflg);
         return err;
 }
 
diff -urN linux/kernel/Makefile linux-2.2.14/kernel/Makefile
--- linux/kernel/Makefile Wed May 6 14:01:46 1998
+++ linux-2.2.14/kernel/Makefile Mon Mar 27 03:07:08 2000
@@ -25,6 +25,10 @@
 OX_OBJS += ksyms.o
 endif
 
+ifdef CONFIG_TRACE
+OX_OBJS += trace.o
+endif
+
 CFLAGS_sched.o := $(PROFILING) -fno-omit-frame-pointer
 
 include $(TOPDIR)/Rules.make
diff -urN linux/kernel/exit.c linux-2.2.14/kernel/exit.c
--- linux/kernel/exit.c Tue Jan 4 13:12:25 2000
+++ linux-2.2.14/kernel/exit.c Mon Mar 27 03:08:37 2000
@@ -14,6 +14,8 @@
 #include <linux/acct.h>
 #endif
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
@@ -385,6 +387,8 @@
         del_timer(&tsk->real_timer);
         end_bh_atomic();
 
+ TRACE_PROCESS(TRACE_EV_PROCESS_EXIT, 0, 0);
+
         lock_kernel();
 fake_volatile:
 #ifdef CONFIG_BSD_PROCESS_ACCT
@@ -439,6 +443,8 @@
 
         if (options & ~(WNOHANG|WUNTRACED|__WCLONE))
                 return -EINVAL;
+
+ TRACE_PROCESS(TRACE_EV_PROCESS_WAIT, pid, 0);
 
         add_wait_queue(&current->wait_chldexit,&wait);
 repeat:
diff -urN linux/kernel/fork.c linux-2.2.14/kernel/fork.c
--- linux/kernel/fork.c Tue Oct 26 20:53:42 1999
+++ linux-2.2.14/kernel/fork.c Mon Mar 27 03:09:50 2000
@@ -18,6 +18,8 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 
+#include <linux/trace.h>
+
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
 #include <asm/uaccess.h>
@@ -716,6 +718,10 @@
 
                 p->next_run = NULL;
                 p->prev_run = NULL;
+
+ /* Trace the event */
+ TRACE_PROCESS(TRACE_EV_PROCESS_FORK, retval, 0);
+
                 wake_up_process(p); /* do this last */
         }
         ++total_forks;
diff -urN linux/kernel/itimer.c linux-2.2.14/kernel/itimer.c
--- linux/kernel/itimer.c Tue Nov 24 16:51:44 1998
+++ linux-2.2.14/kernel/itimer.c Mon Mar 27 03:11:08 2000
@@ -10,6 +10,8 @@
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 /*
@@ -94,6 +96,7 @@
         struct task_struct * p = (struct task_struct *) __data;
         unsigned long interval;
 
+ TRACE_TIMER(TRACE_EV_TIMER_EXPIRED, 0, 0, 0);
         send_sig(SIGALRM, p, 1);
         interval = p->it_real_incr;
         if (interval) {
@@ -113,6 +116,7 @@
         j = tvtojiffies(&value->it_value);
         if (ovalue && (k = do_getitimer(which, ovalue)) < 0)
                 return k;
+ TRACE_TIMER(TRACE_EV_TIMER_SETITIMER, which, i, j);
         switch (which) {
                 case ITIMER_REAL:
                         start_bh_atomic();
diff -urN linux/kernel/sched.c linux-2.2.14/kernel/sched.c
--- linux/kernel/sched.c Tue Jan 4 13:12:25 2000
+++ linux-2.2.14/kernel/sched.c Mon Mar 27 03:13:18 2000
@@ -32,6 +32,8 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -445,6 +447,8 @@
 {
         unsigned long flags;
 
+ TRACE_PROCESS(TRACE_EV_PROCESS_WAKEUP, p->pid, p->state);
+
         /*
          * We want the common case fall through straight, thus the goto.
          */
@@ -465,6 +469,7 @@
 {
         struct task_struct * p = (struct task_struct *) __data;
 
+ TRACE_TIMER(TRACE_EV_TIMER_EXPIRED, 0, 0, 0);
         wake_up_process(p);
 }
 
@@ -635,6 +640,8 @@
                 }
         }
 
+ TRACE_TIMER(TRACE_EV_TIMER_SETTIMEOUT, 0, timeout, 0);
+
         expire = timeout + jiffies;
 
         init_timer(&timer);
@@ -820,6 +827,7 @@
 
         kstat.context_swtch++;
         get_mmu_context(next);
+ TRACE_SCHEDCHANGE(prev->pid, next->pid, prev->state);
         switch_to(prev, next, prev);
         __schedule_tail(prev);
 
@@ -1524,6 +1532,7 @@
 
 static void timer_bh(void)
 {
+ TRACE_EVENT(TRACE_EV_KERNEL_TIMER, NULL);
         update_times();
         run_old_timers();
         run_timer_list();
diff -urN linux/kernel/signal.c linux-2.2.14/kernel/signal.c
--- linux/kernel/signal.c Tue Jan 4 13:12:26 2000
+++ linux-2.2.14/kernel/signal.c Mon Mar 27 03:15:19 2000
@@ -13,6 +13,8 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 /*
@@ -281,6 +283,8 @@
                 spin_unlock_irqrestore(&t->sigmask_lock, flags);
                 goto out_nolock;
         }
+
+ TRACE_PROCESS(TRACE_EV_PROCESS_SIGNAL, sig, t->pid);
 
         switch (sig) {
         case SIGKILL: case SIGCONT:
diff -urN linux/kernel/softirq.c linux-2.2.14/kernel/softirq.c
--- linux/kernel/softirq.c Sun Mar 21 10:22:00 1999
+++ linux-2.2.14/kernel/softirq.c Mon Mar 27 03:17:03 2000
@@ -16,6 +16,8 @@
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
 
+#include <linux/trace.h>
+
 #include <asm/io.h>
 
 /* intr_count died a painless death... -DaveM */
@@ -47,8 +49,10 @@
         clear_active_bhs(active);
         bh = bh_base;
         do {
- if (active & 1)
+ if (active & 1){
+ TRACE_BOTTOM_HALF((bh-bh_base));
                         (*bh)();
+ }
                 bh++;
                 active >>= 1;
         } while (active);
diff -urN linux/kernel/trace.c linux-2.2.14/kernel/trace.c
--- linux/kernel/trace.c Wed Dec 31 19:00:00 1969
+++ linux-2.2.14/kernel/trace.c Mon Mar 27 03:17:50 2000
@@ -0,0 +1,189 @@
+/*
+ * linux/kernel/trace.c
+ *
+ * (C) Copyright 1999 - Karim Yaghmour
+ *
+ * This code is distributed under the GPL license
+ *
+ * Tracing management
+ *
+ */
+
+#include <linux/trace.h> /* Tracing definitions */
+#include <linux/errno.h> /* Miscellaneous error codes */
+#include <linux/stddef.h> /* NULL */
+#include <linux/malloc.h> /* kmalloc() */
+#include <linux/module.h> /* EXPORT_SYMBOL */
+
+/* Local variables */
+static int tracer_registered = 0; /* Is there a tracer registered */
+struct tracer * tracer = NULL; /* The registered tracer */
+
+/****************************************************
+ * Register the tracer to the kernel
+ * Return values :
+ * 0, all is OK
+ * -EBUSY, there already is a registered tracer
+ * -ENOMEM, couldn't allocate memory
+ ****************************************************/
+int register_tracer(tracer_call pmTraceFunction)
+{
+ /* Is there a tracer already registered */
+ if(tracer_registered == 1)
+ return -EBUSY;
+
+ /* Allocate memory for the tracer */
+ if((tracer = (struct tracer *) kmalloc(sizeof(struct tracer), GFP_KERNEL)) == NULL)
+ /* We couldn't allocate any memory */
+ return -ENOMEM;
+
+ /* There is a tracer registered */
+ tracer_registered = 1;
+
+ /* Set the tracer to the one being passed by the caller */
+ tracer->trace = pmTraceFunction;
+
+ /* Initialize the tracer settings */
+ tracer->fetch_syscall_eip_use_bounds = 0;
+ tracer->fetch_syscall_eip_use_depth = 0;
+
+ /* Tell the caller that everything went fine */
+ return 0;
+}
+
+/***************************************************
+ * Unregister the currently registered tracer
+ * Return values :
+ * 0, all is OK
+ * -ENOMEDIUM, there isn't a registered tracer
+ * -ENXIO, unregestering wrong tracer
+ ***************************************************/
+int unregister_tracer(tracer_call pmTraceFunction)
+{
+ /* Is there a tracer already registered */
+ if(tracer_registered == 0)
+ /* Nothing to unregister */
+ return -ENOMEDIUM;
+
+ /* Is it the tracer that was registered */
+ if(tracer->trace == pmTraceFunction)
+ /* There isn't any tracer in here */
+ tracer_registered = 0;
+ else
+ return -ENXIO;
+
+ /* Free the memory used by the tracing structure */
+ kfree(tracer);
+ tracer = NULL;
+
+ /* Tell the caller that everything went OK */
+ return 0;
+}
+
+/*******************************************************
+ * Set the tracing configuration
+ * Parameters :
+ * pmTraceFunction, the trace function.
+ * pmFetchSyscallUseDepth, Use depth to fetch eip
+ * pmFetchSyscallUseBounds, Use bounds to fetch eip
+ * pmSyscallEipDepth, Detph to fetch eip
+ * pmSyscallLowerBound, Lower bound eip address
+ * pmSyscallUpperBound, Upper bound eip address
+ * Return values :
+ * 0, all is OK
+ * -ENOMEDIUM, there isn't a registered tracer
+ * -ENXIO, wrong tracer
+ * -EINVAL, invalid configuration
+ *******************************************************/
+int trace_set_config(tracer_call pmTraceFunction,
+ int pmFetchSyscallUseDepth,
+ int pmFetchSyscallUseBounds,
+ int pmSyscallEipDepth,
+ void* pmSyscallLowerBound,
+ void* pmSyscallUpperBound)
+{
+ /* Is there a tracer already registered */
+ if(tracer_registered == 0)
+ return -ENOMEDIUM;
+
+ /* Is it the tracer that was registered */
+ if(tracer->trace != pmTraceFunction)
+ return -ENXIO;
+
+ /* Is this a valid configuration */
+ if((pmFetchSyscallUseDepth && pmFetchSyscallUseBounds)
+ ||(pmSyscallLowerBound > pmSyscallUpperBound)
+ ||(pmSyscallEipDepth < 0))
+ return -EINVAL;
+
+ /* Set the configuration */
+ tracer->fetch_syscall_eip_use_depth = pmFetchSyscallUseDepth;
+ tracer->fetch_syscall_eip_use_bounds = pmFetchSyscallUseBounds;
+ tracer->syscall_eip_depth = pmSyscallEipDepth;
+ tracer->syscall_lower_eip_bound = pmSyscallLowerBound;
+ tracer->syscall_upper_eip_bound = pmSyscallUpperBound;
+
+ /* Tell the caller that everything was OK */
+ return 0;
+}
+
+/*******************************************************
+ * Get the tracing configuration
+ * Parameters :
+ * pmFetchSyscallUseDepth, Use depth to fetch eip
+ * pmFetchSyscallUseBounds, Use bounds to fetch eip
+ * pmSyscallEipDepth, Detph to fetch eip
+ * pmSyscallLowerBound, Lower bound eip address
+ * pmSyscallUpperBound, Upper bound eip address
+ * Return values :
+ * 0, all is OK
+ * -ENOMEDIUM, there isn't a registered tracer
+ *******************************************************/
+int trace_get_config(int* pmFetchSyscallUseDepth,
+ int* pmFetchSyscallUseBounds,
+ int* pmSyscallEipDepth,
+ void** pmSyscallLowerBound,
+ void** pmSyscallUpperBound)
+{
+ /* Is there a tracer already registered */
+ if(tracer_registered == 0)
+ return -ENOMEDIUM;
+
+ /* Get the configuration */
+ *pmFetchSyscallUseDepth = tracer->fetch_syscall_eip_use_depth;
+ *pmFetchSyscallUseBounds = tracer->fetch_syscall_eip_use_bounds;
+ *pmSyscallEipDepth = tracer->syscall_eip_depth;
+ *pmSyscallLowerBound = tracer->syscall_lower_eip_bound;
+ *pmSyscallUpperBound = tracer->syscall_upper_eip_bound;
+
+ /* Tell the caller that everything was OK */
+ return 0;
+}
+
+/*******************************************************
+ * Trace an event
+ * Parameters :
+ * pmEventID, the event's ID (check out trace.h)
+ * pmEventStruct, the structure describing the event
+ * Return values :
+ * 0, all is OK
+ * -ENOMEDIUM, there isn't a registered tracer
+ * -EBUSY, tracing hasn't started yet
+ *******************************************************/
+int trace_event(uint8_t pmEventID,
+ void* pmEventStruct)
+{
+ /* Is there a tracer registered */
+ if(tracer_registered != 1)
+ return -ENOMEDIUM;
+
+ /* Call the tracer */
+ return (tracer->trace(pmEventID, pmEventStruct));
+}
+
+/* Export symbols so that can be visible from outside this file */
+EXPORT_SYMBOL(register_tracer);
+EXPORT_SYMBOL(unregister_tracer);
+EXPORT_SYMBOL(trace_set_config);
+EXPORT_SYMBOL(trace_get_config);
+EXPORT_SYMBOL(trace_event);
diff -urN linux/mm/filemap.c linux-2.2.14/mm/filemap.c
--- linux/mm/filemap.c Tue Jan 4 13:12:26 2000
+++ linux-2.2.14/mm/filemap.c Mon Mar 27 03:19:05 2000
@@ -22,6 +22,8 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
@@ -335,12 +337,14 @@
         add_wait_queue(&page->wait, &wait);
 repeat:
         tsk->state = TASK_UNINTERRUPTIBLE;
+ TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_WAIT_START, 0);
         run_task_queue(&tq_disk);
         if (PageLocked(page)) {
                 schedule();
                 goto repeat;
         }
         tsk->state = TASK_RUNNING;
+ TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_WAIT_END, 0);
         remove_wait_queue(&page->wait, &wait);
 }
 
diff -urN linux/mm/page_alloc.c linux-2.2.14/mm/page_alloc.c
--- linux/mm/page_alloc.c Tue Jan 4 13:12:26 2000
+++ linux-2.2.14/mm/page_alloc.c Mon Mar 27 03:20:38 2000
@@ -14,6 +14,8 @@
 #include <linux/init.h>
 #include <linux/pagemap.h>
 
+#include <linux/trace.h>
+
 #include <asm/dma.h>
 #include <asm/uaccess.h> /* for copy_to/from_user */
 #include <asm/pgtable.h>
@@ -100,6 +102,8 @@
         unsigned long mask = (~0UL) << order;
         unsigned long flags;
 
+ TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_FREE, order);
+
         spin_lock_irqsave(&page_alloc_lock, flags);
 
 #define list(x) (mem_map+(x))
@@ -237,6 +241,8 @@
         RMQUEUE_TYPE(order, 1);
         spin_unlock_irqrestore(&page_alloc_lock, flags);
 
+ TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_ALLOC, order);
+
         /*
          * If we can schedule, do so, and make sure to yield.
          * We may be a real-time process, and if kswapd is
@@ -410,6 +416,8 @@
         vma->vm_mm->rss++;
         tsk->min_flt++;
         swap_free(entry);
+
+ TRACE_MEMORY(TRACE_EV_MEMORY_SWAP_IN, page);
 
         if (!write_access || is_page_shared(page_map)) {
                 set_pte(page_table, mk_pte(page, vma->vm_page_prot));
diff -urN linux/mm/vmscan.c linux-2.2.14/mm/vmscan.c
--- linux/mm/vmscan.c Tue Jan 4 13:12:26 2000
+++ linux-2.2.14/mm/vmscan.c Mon Mar 27 03:21:40 2000
@@ -18,6 +18,8 @@
 #include <linux/pagemap.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/pgtable.h>
 
 /*
@@ -160,6 +162,8 @@
         /* We checked we were unlocked way up above, and we
            have been careful not to stall until here */
         set_bit(PG_locked, &page_map->flags);
+
+ TRACE_MEMORY(TRACE_EV_MEMORY_SWAP_OUT, page);
 
         /* OK, do a physical asynchronous write to swap. */
         rw_swap_page(WRITE, entry, (char *) page, 0);
diff -urN linux/net/core/dev.c linux-2.2.14/net/core/dev.c
--- linux/net/core/dev.c Tue Jan 4 13:12:26 2000
+++ linux-2.2.14/net/core/dev.c Mon Mar 27 03:23:17 2000
@@ -93,6 +93,9 @@
 #ifdef CONFIG_NET_RADIO
 #include <linux/wireless.h>
 #endif /* CONFIG_NET_RADIO */
+
+#include <linux/trace.h>
+
 #ifdef CONFIG_PLIP
 extern int plip_init(void);
 #endif
@@ -586,6 +589,9 @@
         NET_PROFILE_ENTER(dev_queue_xmit);
 #endif
 
+ /* Trace the event */
+ TRACE_NETWORK(TRACE_EV_NETWORK_PACKET_OUT, skb->protocol);
+
         start_bh_atomic();
         q = dev->qdisc;
         if (q->enqueue) {
@@ -884,6 +890,9 @@
                  * We have a packet. Therefore the queue has shrunk
                  */
                 skb = skb_dequeue(&backlog);
+
+ /* Trace this event */
+ TRACE_NETWORK(TRACE_EV_NETWORK_PACKET_IN, skb->protocol);
 
 #ifdef CONFIG_CPU_IS_SLOW
                 if (ave_busy > 128*16) {
diff -urN linux/net/socket.c linux-2.2.14/net/socket.c
--- linux/net/socket.c Thu Apr 22 22:45:20 1999
+++ linux-2.2.14/net/socket.c Mon Mar 27 03:25:27 2000
@@ -73,6 +73,8 @@
 #include <linux/kmod.h>
 #endif
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 #include <linux/inet.h>
@@ -327,6 +329,8 @@
         int err;
         struct scm_cookie scm;
 
+ TRACE_SOCKET(TRACE_EV_SOCKET_SEND, sock->type, size);
+
         err = scm_send(sock, msg, &scm);
         if (err >= 0) {
                 err = sock->ops->sendmsg(sock, msg, size, &scm);
@@ -341,6 +345,8 @@
 
         memset(&scm, 0, sizeof(scm));
 
+ TRACE_SOCKET(TRACE_EV_SOCKET_RECEIVE, sock->type, size);
+
         size = sock->ops->recvmsg(sock, msg, size, flags, &scm);
         if (size >= 0)
                 scm_recv(sock, msg, &scm, flags);
@@ -652,6 +658,8 @@
                 goto out_release;
         sock->file = fcheck(retval);
 
+ TRACE_SOCKET(TRACE_EV_SOCKET_CREATE, retval, type);
+
 out:
         unlock_kernel();
         return retval;
@@ -1329,6 +1337,7 @@
         a0=a[0];
         a1=a[1];
         
+ TRACE_SOCKET(TRACE_EV_SOCKET_CALL, call, a0);
         switch(call)
         {
                 case SYS_SOCKET:

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Mar 31 2000 - 21:00:20 EST