This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

proof-of-concept, utrace->ftrace engine


Hi -

Here's the start of a little ditty that ties process-related events as
hooked by the Roland McGrath's utrace code into the ftrace
buffer/control widgetry.  If nothing else, think of it as one
potential in-tree user of utrace.


Script started on Tue 27 Jan 2009 02:39:06 PM EST

[root@vm-fed10-64 tracing]# cat available_tracers 
process wakeup irqsoff sysprof sched_switch nop
[root@vm-fed10-64 tracing]# echo process > current_tracer 
[root@vm-fed10-64 tracing]# echo 500 > process_trace_uid_filter 
[root@vm-fed10-64 tracing]# cat trace
# tracer: process
#
#           TASK-PID    CPU#    TIMESTAMP  FUNCTION
#              | |       |          |         |
[root@vm-fed10-64 tracing]# su - fche
%                                                                               
vm-fed10-64 /home/fche
[14:39:50] % pwd
/home/fche
%                                                                               
vm-fed10-64 /home/fche
[14:39:52] % ls /tmp
firstbootX.log     pulse-PKdhtXMmr18n  stapbXg0xB  stapUniATd
foo                stap6cNJ5M          stapl9Ww2f  virtual-fche.4SkpzQ
kerneloops.pxnITL  stap9MajHI          stapT1LKnQ
%                                                                               
vm-fed10-64 /home/fche
[14:39:59] % df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
                      13706328  11417980   2149176  85% /
/dev/sda1               194442     34259    150144  19% /boot
tmpfs                   382320         0    382320   0% /dev/shm
super:/home          1300999168 496440320 750835712  40% /home
%                                                                               
vm-fed10-64 /home/fche
[14:40:03] % exit
Tue Jan 27 14:40:05 EST 2009
[root@vm-fed10-64 tracing]# cat trace
# tracer: process
#
#           TASK-PID    CPU#    TIMESTAMP  FUNCTION
#              | |       |          |         |
             zsh  2091   0   2616701.950948 exec
             zsh  2091   0   2616701.966410 fork 2092 flags 0x1200011
          whoami  2092   1   2616702.005276 exec
          whoami  2092   0   2616702.008612 exit 0
             zsh  2091   0   2616702.009193 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.011385 fork 2093 flags 0x1200011
           mkdir  2093   1   2616702.013701 exec
           mkdir  2093   0   2616702.017300 exit 0
             zsh  2091   0   2616702.018133 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.018951 fork 2094 flags 0x1200011
          whoami  2094   0   2616702.023867 exec
          whoami  2094   0   2616702.026108 exit 0
             zsh  2091   0   2616702.026567 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.027358 fork 2095 flags 0x1200011
           mkdir  2095   1   2616702.029712 exec
           mkdir  2095   1   2616702.031703 exit 0
             zsh  2091   0   2616702.032275 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.035062 fork 2096 flags 0x1200011
             zsh  2096   1   2616702.036457 exit 0
             zsh  2091   0   2616702.037344 fork 2097 flags 0x1200011
             zsh  2091   0   2616702.038959 signal 17 errno 0 code 262145
           egrep  2097   1   2616702.039692 exec
           egrep  2097   1   2616702.041620 exit 256
             zsh  2091   0   2616702.042150 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.043095 fork 2098 flags 0x1200011
             zsh  2098   1   2616702.044435 exit 0
             zsh  2091   0   2616702.045329 fork 2099 flags 0x1200011
             zsh  2091   0   2616702.046846 signal 17 errno 0 code 262145
           egrep  2099   1   2616702.047646 exec
           egrep  2099   1   2616702.049571 exit 0
             zsh  2091   0   2616702.050141 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.051020 fork 2100 flags 0x1200011
             zsh  2100   0   2616702.052046 exit 0
             zsh  2091   0   2616702.053346 fork 2101 flags 0x1200011
             zsh  2091   0   2616702.054672 signal 17 errno 0 code 262145
           egrep  2101   1   2616702.055515 exec
           egrep  2101   1   2616702.057346 exit 0
             zsh  2091   0   2616702.057907 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.058982 fork 2102 flags 0x1200011
              id  2102   1   2616702.064822 exec
              id  2102   1   2616702.067609 exit 0
             zsh  2091   0   2616702.068307 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.069246 fork 2103 flags 0x1200011
        hostname  2103   0   2616702.072067 exec
        hostname  2103   0   2616702.074154 exit 0
             zsh  2091   0   2616702.074766 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.076529 fork 2104 flags 0x1200011
             zsh  2104   1   2616702.077982 exit 0
             zsh  2091   0   2616702.079742 fork 2105 flags 0x1200011
             zsh  2091   0   2616702.081672 signal 17 errno 0 code 262145
            grep  2105   1   2616702.082929 exec
            grep  2105   0   2616702.087867 exec
            grep  2105   0   2616702.089716 exit 256
             zsh  2091   0   2616702.090205 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.092925 fork 2106 flags 0x1200011
            tput  2106   1   2616702.099077 exec
            tput  2106   1   2616702.100918 exit 0
             zsh  2091   0   2616702.101588 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.102659 fork 2107 flags 0x1200011
       dircolors  2107   1   2616702.108917 exec
       dircolors  2107   1   2616702.110359 exit 0
             zsh  2091   0   2616702.110997 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.134110 fork 2108 flags 0x1200011
           egrep  2108   0   2616702.136910 exec
           egrep  2108   0   2616702.138921 exit 256
             zsh  2091   0   2616702.139430 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.141230 fork 2109 flags 0x1200011
             zsh  2109   1   2616702.142714 exit 0
             zsh  2091   0   2616702.143685 fork 2110 flags 0x1200011
             zsh  2091   0   2616702.145204 signal 17 errno 0 code 262145
            grep  2110   1   2616702.145974 exec
            grep  2110   1   2616702.147934 exit 256
             zsh  2091   0   2616702.150523 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.151842 fork 2111 flags 0x1200011
             zsh  2111   1   2616702.153271 exit 0
             zsh  2091   0   2616702.154703 fork 2112 flags 0x1200011
             zsh  2091   0   2616702.156063 signal 17 errno 0 code 262145
            grep  2112   1   2616702.157028 exec
            grep  2112   1   2616702.158834 exit 256
             zsh  2091   0   2616702.159476 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.160319 fork 2113 flags 0x1200011
              id  2113   1   2616702.162848 exec
              id  2113   1   2616702.165115 exit 0
             zsh  2091   0   2616702.165872 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.168590 fork 2114 flags 0x1200011
     consoletype  2114   1   2616702.171021 exec
     consoletype  2114   1   2616702.171988 exit 512
             zsh  2091   0   2616702.172443 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.181959 fork 2115 flags 0x1200011
          whoami  2115   1   2616702.188936 exec
          whoami  2115   1   2616702.191366 exit 0
             zsh  2091   0   2616702.192051 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.194605 fork 2116 flags 0x1200011
           mkdir  2116   0   2616702.197377 exec
           mkdir  2116   0   2616702.199480 exit 0
             zsh  2091   0   2616702.200084 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.201017 fork 2117 flags 0x1200011
          whoami  2117   0   2616702.206033 exec
          whoami  2117   0   2616702.208245 exit 0
             zsh  2091   0   2616702.208888 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.209836 fork 2118 flags 0x1200011
           mkdir  2118   0   2616702.212527 exec
           mkdir  2118   0   2616702.214474 exit 0
             zsh  2091   0   2616702.215117 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.217011 fork 2119 flags 0x1200011
            stty  2119   0   2616702.220137 exec
            stty  2119   0   2616702.223496 exit 0
             zsh  2091   0   2616702.223977 signal 17 errno 0 code 262145
             zsh  2091   0   2616702.229063 fork 2120 flags 0x1200011
            mesg  2120   0   2616702.232073 exec
            mesg  2120   0   2616702.233994 exit 0
             zsh  2091   0   2616702.234454 signal 17 errno 0 code 262145
             zsh  2091   0   2616711.333172 fork 2121 flags 0x1200011
              ls  2121   0   2616711.336055 exec
              ls  2121   0   2616711.356496 exit 0
             zsh  2091   0   2616711.364547 signal 17 errno 0 code 262145
             zsh  2091   0   2616714.474787 fork 2125 flags 0x1200011
              df  2125   0   2616714.479280 exec
              df  2125   0   2616714.483010 exit 0
             zsh  2091   0   2616714.483701 signal 17 errno 0 code 262145
             zsh  2091   0   2616716.594615 fork 2126 flags 0x1200011
           clear  2126   0   2616716.598083 exec
           clear  2126   0   2616716.599856 exit 0
             zsh  2091   0   2616716.600439 signal 17 errno 0 code 262145
             zsh  2091   0   2616716.601532 fork 2127 flags 0x1200011
            date  2127   0   2616716.613852 exec
            date  2127   0   2616716.619608 exit 0
             zsh  2091   0   2616716.620334 signal 17 errno 0 code 262145
             zsh  2091   0   2616716.632090 fork 2128 flags 0x1200011
           clear  2128   0   2616716.634284 exec
           clear  2128   0   2616716.636012 exit 0
             zsh  2091   0   2616716.636775 signal 17 errno 0 code 262145
             zsh  2091   0   2616716.637448 exit 0
[root@vm-fed10-64 tracing]# nop > current_tracer 
[root@vm-fed10-64 tracing]# cat trace
# tracer: nop
#
#           TASK-PID    CPU#    TIMESTAMP  FUNCTION
#              | |       |          |         |
[root@vm-fed10-64 tracing]# exit

Script done on Tue 27 Jan 2009 02:40:26 PM EST



diff --git a/include/linux/processtrace.h b/include/linux/processtrace.h
new file mode 100644
index 0000000..f902443
--- /dev/null
+++ b/include/linux/processtrace.h
@@ -0,0 +1,33 @@
+#ifndef PROCESSTRACE_H
+#define PROCESSTRACE_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct process_trace_entry {
+	unsigned char opcode;	/* one of _UTRACE_EVENT_* */
+        char comm[TASK_COMM_LEN]; /* XXX: should be in/via trace_entry */
+        union {
+                struct {
+                        pid_t child;
+                        unsigned long flags;
+                } trace_clone;
+                struct {
+                        long code;
+                } trace_exit;
+                struct {
+                } trace_exec;
+                struct {
+                        int si_signo;
+                        int si_errno;
+                        int si_code;
+                } trace_signal;
+        };
+};
+
+/* in kernel/trace/trace_process.c */
+
+extern void enable_process_trace (void);
+extern void disable_process_trace (void);
+
+#endif /* PROCESSTRACE_H */
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 33dbefd..9276863 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -119,6 +119,15 @@ config CONTEXT_SWITCH_TRACER
 	  This tracer gets called from the context switch and records
 	  all switching of tasks.
 
+config PROCESS_TRACER
+	bool "Trace process events via utrace"
+	depends on DEBUG_KERNEL
+	select TRACING
+	select UTRACE
+	help
+	  This tracer provides trace records from process events
+	  accessible to utrace: lifecycle, system calls, and signals.
+
 config BOOT_TRACER
 	bool "Trace boot initcalls"
 	depends on DEBUG_KERNEL
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index c8228b1..b06a5d6 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -24,5 +24,6 @@ obj-$(CONFIG_NOP_TRACER) += trace_nop.o
 obj-$(CONFIG_STACK_TRACER) += trace_stack.o
 obj-$(CONFIG_MMIOTRACE) += trace_mmiotrace.o
 obj-$(CONFIG_BOOT_TRACER) += trace_boot.o
+obj-$(CONFIG_PROCESS_TRACER) += trace_process.o
 
 libftrace-y := ftrace.o
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 8465ad0..7c0cd57 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -7,6 +7,7 @@
 #include <linux/clocksource.h>
 #include <linux/ring_buffer.h>
 #include <linux/mmiotrace.h>
+#include <linux/processtrace.h>
 #include <linux/ftrace.h>
 
 enum trace_type {
@@ -22,6 +23,7 @@ enum trace_type {
 	TRACE_MMIO_RW,
 	TRACE_MMIO_MAP,
 	TRACE_BOOT,
+	TRACE_PROCESS,
 
 	__TRACE_LAST_TYPE
 };
@@ -117,6 +119,11 @@ struct trace_boot {
 	struct boot_trace	initcall;
 };
 
+struct trace_process {
+        struct trace_entry		ent;
+	struct process_trace_entry	event;
+};
+
 /*
  * trace_flag_type is an enumeration that holds different
  * states when a trace occurs. These are:
@@ -219,6 +226,7 @@ extern void __ftrace_bad_type(void);
 		IF_ASSIGN(var, ent, struct trace_mmiotrace_map,		\
 			  TRACE_MMIO_MAP);				\
 		IF_ASSIGN(var, ent, struct trace_boot, TRACE_BOOT);	\
+		IF_ASSIGN(var, ent, struct trace_process, TRACE_PROCESS); \
 		__ftrace_bad_type();					\
 	} while (0)
 
diff --git a/kernel/trace/trace_process.c b/kernel/trace/trace_process.c
new file mode 100644
index 0000000..10c2c3c
--- /dev/null
+++ b/kernel/trace/trace_process.c
@@ -0,0 +1,440 @@
+/*
+ * utrace-based process event tracing
+ * Copyright (C) 2009 Red Hat Inc.
+ * By Frank Ch. Eigler <fche@redhat.com>
+ */
+
+#define DEBUG 1
+
+#include <linux/kernel.h>
+#include <linux/utrace.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+
+#include "trace.h"
+
+/* A process must match these filters in order to be traced. */
+static char trace_taskcomm_filter[TASK_COMM_LEN]; /* \0: unrestricted */
+static u32 trace_taskuid_filter = -1; /* -1: unrestricted */
+
+/* A process must be a direct child of given pid in order to be
+   followed. */ 
+static u32 process_follow_pid; /* 0: unrestricted/systemwide */
+
+/* XXX: lock the above? */
+
+
+/* trace data collection */
+
+static struct trace_array *process_trace_array;
+
+static void process_reset_data(struct trace_array *tr)
+{
+	int cpu;
+
+	pr_debug("in %s\n", __func__);
+	tr->time_start = ftrace_now(tr->cpu);
+	for_each_online_cpu(cpu)
+		tracing_reset(tr, cpu);
+}
+
+static void process_trace_init(struct trace_array *tr)
+{
+	pr_debug("in %s\n", __func__);
+	process_trace_array = tr;
+	if (tr->ctrl) {
+		process_reset_data(tr);
+		enable_process_trace();
+	}
+}
+
+static void process_trace_reset(struct trace_array *tr)
+{
+	pr_debug("in %s\n", __func__);
+	if (tr->ctrl)
+		disable_process_trace();
+	process_reset_data(tr);
+	process_trace_array = NULL;
+}
+
+static void process_trace_ctrl_update(struct trace_array *tr)
+{
+	pr_debug("in %s\n", __func__);
+	if (tr->ctrl) {
+		process_reset_data(tr);
+		enable_process_trace();
+	} else {
+		disable_process_trace();
+	}
+}
+
+static void __trace_processtrace(struct trace_array *tr,
+				struct trace_array_cpu *data,
+				struct process_trace_entry *ent)
+{
+	struct ring_buffer_event *event;
+	struct trace_process *entry;
+	unsigned long irq_flags;
+
+	event	= ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
+					   &irq_flags);
+	if (!event)
+		return;
+	entry	= ring_buffer_event_data(event);
+	tracing_generic_entry_update(&entry->ent, 0, preempt_count());
+        entry->ent.cpu                  = raw_smp_processor_id();
+	entry->ent.type			= TRACE_PROCESS;
+        strlcpy (ent->comm, current->comm, TASK_COMM_LEN);
+	entry->event			= *ent;
+	ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
+
+	trace_wake_up();
+}
+
+void process_trace(struct process_trace_entry *ent)
+{
+	struct trace_array *tr = process_trace_array;
+	struct trace_array_cpu *data = tr->data[smp_processor_id()];
+
+	__trace_processtrace(tr, data, ent);
+}
+
+
+/* trace data rendering */
+
+static void process_pipe_open(struct trace_iterator *iter)
+{
+	struct trace_seq *s = &iter->seq;
+	pr_debug("in %s\n", __func__);
+	trace_seq_printf(s, "VERSION 200901\n");
+}
+
+static void process_close(struct trace_iterator *iter)
+{
+	iter->private = NULL;
+}
+
+static ssize_t process_read(struct trace_iterator *iter, struct file *filp,
+				char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	ssize_t ret;
+	struct trace_seq *s = &iter->seq;
+	ret = trace_seq_to_user(s, ubuf, cnt);
+	return (ret == -EBUSY) ? 0 : ret;
+}
+
+static enum print_line_t process_print(struct trace_iterator *iter)
+{
+	struct trace_entry *entry = iter->ent;
+	struct trace_process *field;
+	struct trace_seq *s	= &iter->seq;
+	unsigned long long t	= ns2usecs(iter->ts);
+	unsigned long usec_rem	= do_div(t, 1000000ULL);
+	unsigned secs		= (unsigned long)t;
+	int ret = 1;
+
+	pr_debug("in %s\n", __func__);
+	trace_assign_type(field, entry);
+
+        /* XXX: If print_lat_fmt() were not static, we wouldn't have
+           to duplicate this. */
+        trace_seq_printf(s, "%16s %5d %3d %9lu.%06ld ",
+                         field->event.comm,
+                         entry->pid, entry->cpu,
+                         secs,
+                         usec_rem);
+
+	switch (field->event.opcode) {
+	case _UTRACE_EVENT_CLONE:
+		ret = trace_seq_printf(s, "fork %d flags 0x%lx\n",
+                                       field->event.trace_clone.child,
+                                       field->event.trace_clone.flags);
+		break;
+	case _UTRACE_EVENT_EXEC:
+		ret = trace_seq_printf(s, "exec\n");
+		break;
+	case _UTRACE_EVENT_EXIT:
+		ret = trace_seq_printf(s, "exit %ld\n",
+                                       field->event.trace_exit.code);
+		break;
+	case _UTRACE_EVENT_SIGNAL:
+		ret = trace_seq_printf(s, "signal %d errno %d code %d\n",
+                                       field->event.trace_signal.si_signo,
+                                       field->event.trace_signal.si_errno,
+                                       field->event.trace_signal.si_code);
+		break;
+	default:
+		ret = trace_seq_printf(s, "process code %d?\n", field->event.opcode);
+		break;
+	}
+	if (ret)
+		return TRACE_TYPE_HANDLED;
+	return TRACE_TYPE_PARTIAL_LINE;
+}
+
+
+static enum print_line_t process_print_line(struct trace_iterator *iter)
+{
+	switch (iter->ent->type) {
+	case TRACE_PROCESS:
+		return process_print(iter);
+	default:
+		return TRACE_TYPE_HANDLED; /* ignore unknown entries */
+	}
+}
+
+static struct tracer process_tracer __read_mostly =
+{
+	.name		= "process",
+	.init		= process_trace_init,
+	.reset		= process_trace_reset,
+	.pipe_open	= process_pipe_open,
+	.close		= process_close,
+	.read		= process_read,
+	.ctrl_update	= process_trace_ctrl_update,
+	.print_line	= process_print_line,
+};
+
+
+
+/* utrace backend */
+
+/* Should tracing apply to given task?  Compare against filter
+   values. */
+static int trace_test (struct task_struct *tsk) 
+{
+        if (trace_taskcomm_filter[0]
+            && strcmp (trace_taskcomm_filter, tsk->comm))
+                return 0;
+        if (trace_taskuid_filter != (u32)-1 
+            && trace_taskuid_filter != task_uid (tsk))
+                return 0;
+
+        return 1;
+}
+
+
+static struct utrace_engine_ops process_trace_ops __read_mostly;
+
+static void process_trace_tryattach (struct task_struct *tsk) 
+{
+        struct utrace_attached_engine *engine;
+        
+        pr_debug("in %s\n", __func__);
+        engine = utrace_attach_task (tsk, UTRACE_ATTACH_CREATE,
+                                     & process_trace_ops, NULL);
+        if (IS_ERR(engine) || (engine == NULL)) {
+                pr_warning ("utrace_attach_task %d (rc %p)\n",
+                            tsk->pid, engine);
+        } else {
+                int rc;
+
+                /* XXX: Why is this not implicit from the fields
+                   set in the process_trace_ops? */
+                rc = utrace_set_events (tsk, engine,
+                                        UTRACE_EVENT(CLONE) |
+                                        UTRACE_EVENT(EXEC) |
+                                        UTRACE_EVENT(SIGNAL) |
+                                        UTRACE_EVENT(EXIT));
+                if (rc == -EINPROGRESS)
+                        rc = utrace_barrier (tsk, engine);
+                if (rc)
+                        pr_warning ("utrace_set_events/barrier rc %d\n", rc);
+                
+                utrace_engine_put (engine);
+                pr_debug("attached in %s to %s(%d)\n", __func__, tsk->comm, tsk->pid);
+        }
+}
+
+
+u32 process_trace_report_clone (enum utrace_resume_action action,
+                                struct utrace_attached_engine *engine,
+                                struct task_struct *parent,
+                                unsigned long clone_flags,
+                                struct task_struct *child) 
+{
+        if (trace_test (parent)) {
+                struct process_trace_entry ent;
+                ent.opcode = _UTRACE_EVENT_CLONE;
+                ent.trace_clone.child = child->pid;
+                ent.trace_clone.flags = clone_flags;
+                process_trace(& ent);
+        }
+
+        process_trace_tryattach (child);
+                        
+        return action;
+}
+
+
+u32 process_trace_report_exec (enum utrace_resume_action action,
+                               struct utrace_attached_engine *engine,
+                               struct task_struct *task,
+                               const struct linux_binfmt *fmt,
+                               const struct linux_binprm *bprm,
+                               struct pt_regs *regs) 
+{
+        if (trace_test (task)) {
+                struct process_trace_entry ent;
+                ent.opcode = _UTRACE_EVENT_EXEC;
+                process_trace(& ent);
+        }
+
+        /* We're already attached; no need for a new tryattach. */
+
+        return action;
+}
+
+
+u32 process_trace_report_signal (u32 action,
+                                 struct utrace_attached_engine *engine,
+                                 struct task_struct *task,
+                                 struct pt_regs *regs,
+                                 siginfo_t *info,
+                                 const struct k_sigaction *orig_ka,
+                                 struct k_sigaction *return_ka)
+{
+        if (trace_test (task)) {
+                struct process_trace_entry ent;
+                ent.opcode = _UTRACE_EVENT_SIGNAL;
+                ent.trace_signal.si_signo = info->si_signo;
+                ent.trace_signal.si_errno = info->si_errno;
+                ent.trace_signal.si_code = info->si_code;
+                process_trace(& ent);
+        }
+
+        /* We're already attached; no need for a new tryattach. */
+
+        return action;
+}
+
+
+u32 process_trace_report_exit (enum utrace_resume_action action,
+                               struct utrace_attached_engine *engine,
+                               struct task_struct *task,
+                               long orig_code, long *code) 
+{
+        if (trace_test (task)) {
+                struct process_trace_entry ent;
+                ent.opcode = _UTRACE_EVENT_EXIT;
+                ent.trace_exit.code = orig_code;
+                process_trace(& ent);
+        }
+
+        /* There is no need to explicitly attach or detach here. */
+
+        return action;
+}
+
+
+void enable_process_trace () { 
+        struct task_struct *grp, *tsk;
+
+        pr_debug("in %s\n", __func__);
+        rcu_read_lock();
+        do_each_thread(grp, tsk) {
+                struct mm_struct *mm;
+
+                /* Skip over kernel threads. */
+                mm = get_task_mm (tsk);
+                if (!mm)
+                        continue;
+                
+                if (process_follow_pid) {
+                        if (tsk->tgid == process_follow_pid ||
+                            tsk->parent->tgid == process_follow_pid)
+                        process_trace_tryattach (tsk);
+                } else {
+                        process_trace_tryattach (tsk);
+                }
+        } while_each_thread(grp, tsk);
+        rcu_read_unlock();
+}
+
+void disable_process_trace () {
+        struct utrace_attached_engine *engine;
+        struct task_struct *grp, *tsk;
+        int rc;
+
+        pr_debug("in %s\n", __func__);
+        rcu_read_lock();
+        do_each_thread(grp, tsk) {
+                if (tsk->pid <= 1)
+                        continue;
+
+                /* Find matching engine, if any.  Returns -ENOENT for
+                   unattached threads. */ 
+                engine = utrace_attach_task (tsk, UTRACE_ATTACH_MATCH_OPS,
+                                             & process_trace_ops, 0);
+                if (IS_ERR(engine)) {
+                        if (PTR_ERR(engine) != -ENOENT)
+                                pr_warning ("utrace_attach_task %d (rc %ld)\n",
+                                            tsk->pid, -PTR_ERR(engine));
+                } else if (engine == NULL) {
+                        pr_warning ("utrace_attach_task %d (null engine)\n",
+                                    tsk->pid);
+                } else {
+                        /* Found one of our own engines.  Detach.  */
+                        rc = utrace_control (tsk, engine, UTRACE_DETACH);
+                        switch (rc) {
+                        case 0:             /* success */
+                                break;
+                        case -ESRCH:        /* REAP callback already begun */
+                        case -EALREADY:     /* DEATH callback already begun */
+                                break;
+                        default:
+                                rc = -rc;
+                                pr_warning ("utrace_detach %d (rc %d)\n",
+                                            tsk->pid, rc);
+                                break;
+                        }
+                        utrace_engine_put(engine);
+                        pr_debug("detached in %s from %s(%d)\n", __func__, tsk->comm, tsk->pid);
+                }
+        } while_each_thread(grp, tsk);
+        rcu_read_unlock();
+}
+
+
+static struct utrace_engine_ops process_trace_ops __read_mostly = {
+        .report_clone = process_trace_report_clone,
+        .report_exec = process_trace_report_exec,
+        .report_exit = process_trace_report_exit,
+        .report_signal = process_trace_report_signal,
+};
+
+
+
+/* control interfaces */
+
+static struct debugfs_blob_wrapper trace_taskcomm_filter_blob = {
+        .data = trace_taskcomm_filter,
+        .size = sizeof (trace_taskcomm_filter),
+};
+
+static __init int init_process_trace(void)
+{
+        struct dentry *d_tracer;
+        struct dentry *entry;
+
+        d_tracer = tracing_init_dentry();
+
+        entry = debugfs_create_blob("process_trace_taskcomm_filter", 0644, d_tracer,
+                                    & trace_taskcomm_filter_blob);
+        if (!entry)
+                pr_warning("Could not create debugfs 'process_trace_taskcomm_filter' entry\n");
+
+        entry = debugfs_create_u32("process_trace_uid_filter", 0644, d_tracer,
+                                   & trace_taskuid_filter);
+        if (!entry)
+                pr_warning("Could not create debugfs 'process_trace_uid_filter' entry\n");
+
+        entry = debugfs_create_u32("process_follow_pid", 0644, d_tracer,
+                                   & process_follow_pid);
+        if (!entry)
+                pr_warning("Could not create debugfs 'process_follow_pid' entry\n");
+
+	return register_tracer(&process_tracer);
+}
+
+device_initcall(init_process_trace);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]