All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Frank Ch. Eigler" <fche@redhat.com>
To: utrace-devel@redhat.com
Cc: systemtap@sources.redhat.com, linux-kernel@vger.kernel.org
Subject: proof-of-concept, utrace->ftrace engine
Date: Tue, 27 Jan 2009 14:54:26 -0500	[thread overview]
Message-ID: <20090127195425.GF32568@redhat.com> (raw)

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);

             reply	other threads:[~2009-01-27 19:54 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-27 19:54 Frank Ch. Eigler [this message]
2009-02-09  7:22 ` proof-of-concept, utrace->ftrace engine Roland McGrath
2009-02-22 22:22   ` utrace-based ftrace "process" engine, v2 Frank Ch. Eigler

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090127195425.GF32568@redhat.com \
    --to=fche@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=systemtap@sources.redhat.com \
    --cc=utrace-devel@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.