First buildable version.
authorJan Kratochvil <jan.kratochvil@redhat.com>
Fri, 24 Dec 2010 08:37:30 +0000 (09:37 +0100)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Fri, 24 Dec 2010 08:37:30 +0000 (09:37 +0100)
.gitignore [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
config/Makefile.am [new file with mode: 0644]
config/staptrace.spec.in [new file with mode: 0644]
configure.ac [new file with mode: 0644]
src/staptrace.c [new file with mode: 0644]
src/staptrace.stp [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..4efb9c4
--- /dev/null
@@ -0,0 +1,27 @@
+COPYING
+INSTALL
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+config.h
+config.h.in
+config.h.in~
+config.log
+config.status
+config/Makefile
+config/Makefile.in
+config/depcomp
+config/install-sh
+config/missing
+configure
+src/.deps
+src/Makefile
+src/Makefile.am
+src/Makefile.in
+src/staptrace
+src/staptrace.o
+stamp-h1
+staptrace.spec
+src/staptrace-staptrace.o
+tags
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..b7f24c5
--- /dev/null
@@ -0,0 +1,21 @@
+# Process this file with automake to create Makefile.in
+# 
+# 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/>.
+
+SUBDIRS = config src
+# po
+
+EXTRA_DIST = staptrace.spec
diff --git a/config/Makefile.am b/config/Makefile.am
new file mode 100644 (file)
index 0000000..c89a0ad
--- /dev/null
@@ -0,0 +1,18 @@
+# Process this file with automake to create Makefile.in
+# 
+# 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/>.
+
+EXTRA_DIST = staptrace.spec.in
diff --git a/config/staptrace.spec.in b/config/staptrace.spec.in
new file mode 100644 (file)
index 0000000..d0e5ebf
--- /dev/null
@@ -0,0 +1,34 @@
+# -*- rpm-spec-*-
+Summary: strace equivalent based on systemtap
+Name: staptrace
+Version: @PACKAGE_VERSION@
+Release: 1
+License: GPLv3+
+Group: Development/Tools
+Source: staptrace-%{version}.tar.xz
+
+%description
+FIXME
+
+%prep
+%setup -q
+
+%build
+%configure
+make
+
+%install
+rm -rf ${RPM_BUILD_ROOT}
+mkdir -p ${RPM_BUILD_ROOT}%{_prefix}
+
+%makeinstall
+
+%clean
+rm -rf ${RPM_BUILD_ROOT}
+
+%files
+%defattr(-,root,root)
+%{_bindir}/staptrace
+%{_datadir}/staptrace
+
+%changelog
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..b6a7e98
--- /dev/null
@@ -0,0 +1,42 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl Configure input file for staptrace.                     -*-autoconf-*-
+dnl 
+dnl Process this file with automake to create Makefile.in
+dnl 
+dnl Copyright (C) 2010 Free Software Foundation, Inc.
+dnl 
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 3 of the License, or
+dnl (at your option) any later version.
+dnl 
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl 
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+AC_INIT([stap trace],[0.1],[http://bugzilla.redhat.com/bugzilla/],[staptrace])
+
+AC_CONFIG_AUX_DIR([config])
+AC_CONFIG_FILES([config/Makefile])
+
+AC_PREREQ(2.63)                        dnl Minimum Autoconf version required.
+
+dnl We use GNU make extensions; automake 1.10 defaults to -Wportability.
+AM_INIT_AUTOMAKE([foreign -Wno-portability dist-xz no-dist-gzip])
+AM_MAINTAINER_MODE
+
+AC_CONFIG_FILES([Makefile])
+AC_CONFIG_HEADERS([config.h])
+
+dnl The RPM spec file.  We substitute a few values in the file.
+AC_CONFIG_FILES([staptrace.spec:config/staptrace.spec.in])
+
+AC_PROG_CC
+
+AC_CONFIG_FILES([src/Makefile])
+
+AC_OUTPUT
diff --git a/src/staptrace.c b/src/staptrace.c
new file mode 100644 (file)
index 0000000..73a7811
--- /dev/null
@@ -0,0 +1,160 @@
+#include <error.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef STAP_SCRIPT_FILENAME
+#error "STAP_SCRIPT_FILENAME is required"
+#endif
+
+#define STRINGIFY(lit) #lit
+#define _(x) gettext (x)
+
+static int opt_d, opt_f, opt_q, opt_p;
+
+/* Script filename.  */
+static char *opt_Z = STRINGIFY (STAP_SCRIPT_FILENAME);
+
+static void *
+xmalloc (size_t size)
+{
+  void *retval = malloc (size);
+
+  if (retval == NULL)
+    error (EXIT_FAILURE, errno, _("memory allocation of %zu bytes"), size);
+
+  return retval;
+}
+
+static void
+usage (int status)
+{
+  printf ("\
+usage: staptrace [-dfq] [-o file] [-p pid] [command [arg ...]]\n\
+                 [-Z <stap script>]\n\
+\n\
+Default -Z is: %s\n\
+",
+         opt_Z);
+  exit (status);
+}
+
+static void
+dump_args (char **args)
+{
+  char **argp;
+
+  for (argp = args; *argp; argp++)
+    {
+      if (argp > args)
+       fputs (", ", stderr);
+      fprintf (stderr, "'%s'", *argp);
+    }
+  fputc ('\n', stderr);
+}
+
+int
+main (int argc, char **argv)
+{
+  char **args, **argp;
+
+  args = xmalloc (sizeof (*args) * argc * 2);
+  argp = args;
+  *argp++ = argv[0];
+
+  for (;;)
+    {
+      int i;
+
+      i = getopt (argc, argv, "+dfqo:p:hZ:");
+      if (i == EOF)
+       break;
+      switch (i)
+       {
+       case 'd':
+         opt_d = 1;
+         break;
+       case 'f':
+         if (opt_f)
+           error (EXIT_FAILURE, 0, _("-ff is unsupported"));
+         *argp++ = "-G";
+         *argp++ = "opt_f=1";
+         opt_f = 1;
+         break;
+       case 'q':
+         *argp++ = "-G";
+         *argp++ = "opt_q=1";
+         opt_q = 1;
+         break;
+       case 'o':
+         *argp++ = "-o";
+         *argp++ = optarg;
+         break;
+       case 'p':
+         *argp++ = "-x";
+         *argp++ = optarg;
+         opt_p = 1;
+         break;
+       case 'Z':
+         opt_Z = optarg;
+         break;
+       case 'h':
+         usage (EXIT_SUCCESS);
+       default:
+         error (0, 0, _("Invalid option '%c'"), i);
+         usage (EXIT_FAILURE);
+       }
+    }
+
+  if ((optind == argc) == !opt_p)
+    usage (EXIT_FAILURE);
+
+  if (optind < argc)
+    {
+      size_t len;
+      int i;
+      char *d;
+      const char *s;
+
+      *argp++ = "-c";
+
+      len = 32;
+      for (i = optind; i < argc; i++)
+       len += 3 + strlen (argv[i]) * 4;
+
+      d = *argp++ = xmalloc (len);
+      d = stpcpy (d, "exec");
+      for (i = optind; i < argc; i++)
+       {
+         *d++ = ' ';
+         *d++ = '\'';
+         for (s = argv[optind]; *s; s++)
+           switch (*s)
+             {
+             case '\'':
+               d = stpcpy (d, "'\\''");
+               break;
+             case '\\':
+               *d++ = '\\';
+               /* FALLTHRU */
+             default:
+               *d++ = *s;
+             }
+         *d++ = '\'';
+       }
+      *d++ = 0;
+    }
+  *argp++ = opt_Z;
+  *argp = NULL;
+
+  if (opt_d)
+    dump_args (args);
+  execvp ("stap", args);
+
+  if (!opt_d)
+    dump_args (args);
+  error (EXIT_FAILURE, errno, "Error executing stap");
+}
diff --git a/src/staptrace.stp b/src/staptrace.stp
new file mode 100644 (file)
index 0000000..bcb9b3f
--- /dev/null
@@ -0,0 +1,158 @@
+#! /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 ()
+    }
+}