+#! /usr/bin/stap
+#
+# Copyright (C) 2010 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+global opt_f
+global opt_q
+
+global trace
+# FIXME: count()?
+global trace_count
+global last_tid
+probe begin
+{
+ trace[target ()] = 1
+ trace_count = 1
+ last_tid = target ()
+}
+
+function heading:string ()
+{
+ if (trace_count > 1)
+ {
+ /* strace really calls TID a "pid". */
+ return sprintf ("[pid %5d] ", tid ())
+ }
+ else
+ return ""
+}
+
+global namea
+
+function destroy (tid:long)
+{
+ delete namea[tid]
+}
+
+function lhs:string (tid:long)
+{
+ return namea[tid]
+}
+probe end
+{
+ foreach (tid in namea)
+ printf ("%s = ? <tracer terminated>\n", lhs (tid))
+}
+
+/* BUG: sleeping function called from invalid context at kernel/mutex.c:94
+%{static DEFINE_MUTEX (tracer_mutex);%}
+function lock ()
+%{
+ mutex_lock (&tracer_mutex);
+%}
+function unlock ()
+%{
+ mutex_unlock (&tracer_mutex);
+%}
+*/
+global dummy
+function lock () { dummy = 1; }
+function unlock () { dummy = 1; }
+
+#probe kprocess.start
+#{
+# trace[pid ()] = 1
+# trace_count++
+#}
+#probe kprocess.exit
+#{
+# trace[pid ()] = 0
+# trace_count--
+#}
+probe kprocess.create
+{
+ if (opt_f && trace[tid ()] != 0)
+ {
+ /* systemtap bug? Why `new_pid' is provided but `new_tid' is not? */
+ new_tid = task_tid (task)
+ trace[new_tid] = 1
+ trace_count++
+ if (!opt_q)
+ printf ("Process %d attached\n", new_tid);
+ }
+}
+
+probe kprocess.release
+{
+ /* systemtap bug? Why `pid' is provided but `tid' is not? */
+ /* systemtap bug? Why `[pt]id' is not called `released_[pt]id' to keep the
+ naming in sync with kprocess.create? */
+ tid = task_tid (task)
+ if (trace[tid] != 0)
+ {
+ if (namea[tid] != "")
+ {
+ printf ("%s = ?\n", lhs (tid))
+ destroy (tid)
+ }
+# FIXME
+ else if (0)
+ {
+ /* systemtap bug? exit_group(2) systemtap calls "exit" and _exit(2)
+ is not caught at all. */
+ lock ()
+ if (last_tid != tid () && namea[last_tid] != "")
+ printf (" <unfinished ...>\n")
+ last_tid = tid
+ printf ("%s_exit(?) = ?\n", heading ())
+ unlock ()
+ }
+ delete trace[tid]
+ trace_count--
+ if (!opt_q)
+ printf ("Process %d detached\n", tid);
+ }
+}
+probe syscall.*
+{
+ if (trace[tid ()] != 0)
+ {
+ lock ()
+ /* Why is mmap() called recursively twice? */
+ if (namea[last_tid] != "")
+ printf (" <unfinished ...>\n")
+ last_tid = tid ();
+ namea[tid ()] = name
+ printf ("%s%s(%s", heading (), name, argstr)
+ unlock ()
+ }
+}
+probe syscall.*.return
+{
+ if (trace[tid ()] != 0)
+ {
+ lock ()
+ if (last_tid != tid () && namea[last_tid] != "")
+ printf (" <unfinished ...>\n")
+ if ((last_tid != tid () && namea[last_tid] != "")
+ || (last_tid == tid () && namea[last_tid] == ""))
+ printf ("%s<... %s resumed> ", heading (), name);
+ last_tid = tid ();
+ printf (") = %s\n", retstr)
+ destroy (tid ())
+ unlock ()
+ }
+}