From 04bde520c6acd8189983a9270366ed197e257624 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Fri, 24 Dec 2010 09:37:30 +0100 Subject: [PATCH] First buildable version. --- .gitignore | 27 ++++++++ Makefile.am | 21 +++++++ config/Makefile.am | 18 ++++++ config/staptrace.spec.in | 34 ++++++++++ configure.ac | 42 +++++++++++++ src/staptrace.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++ src/staptrace.stp | 158 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 460 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile.am create mode 100644 config/Makefile.am create mode 100644 config/staptrace.spec.in create mode 100644 configure.ac create mode 100644 src/staptrace.c create mode 100644 src/staptrace.stp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4efb9c4 --- /dev/null +++ b/.gitignore @@ -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 index 0000000..b7f24c5 --- /dev/null +++ b/Makefile.am @@ -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 . + +SUBDIRS = config src +# po + +EXTRA_DIST = staptrace.spec diff --git a/config/Makefile.am b/config/Makefile.am new file mode 100644 index 0000000..c89a0ad --- /dev/null +++ b/config/Makefile.am @@ -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 . + +EXTRA_DIST = staptrace.spec.in diff --git a/config/staptrace.spec.in b/config/staptrace.spec.in new file mode 100644 index 0000000..d0e5ebf --- /dev/null +++ b/config/staptrace.spec.in @@ -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 index 0000000..b6a7e98 --- /dev/null +++ b/configure.ac @@ -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 . + +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 index 0000000..73a7811 --- /dev/null +++ b/src/staptrace.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include +#include + +#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 ]\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 index 0000000..bcb9b3f --- /dev/null +++ b/src/staptrace.stp @@ -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 . + +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 = ? \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 (" \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 (" \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 (" \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 () + } +} -- 1.8.3.1