summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Brolley <brolley@redhat.com>2009-04-21 11:11:02 -0400
committerDave Brolley <brolley@redhat.com>2009-04-21 11:11:02 -0400
commit09fd19d66b9e3318e9e33f604eb2dbe623955123 (patch)
tree073dc18e4ca3ca4bac674c7225a9a54e5fafc7f7
parentd4935c2f80122827a02d9f66c020d7e8ef6d6ade (diff)
parent9a6d143c6e2c79cee1082d0455da92cfa78b03c7 (diff)
downloadsystemtap-steved-09fd19d66b9e3318e9e33f604eb2dbe623955123.tar.gz
systemtap-steved-09fd19d66b9e3318e9e33f604eb2dbe623955123.tar.xz
systemtap-steved-09fd19d66b9e3318e9e33f604eb2dbe623955123.zip
Merge branch 'master' of git://sources.redhat.com/git/systemtap
Conflicts: aclocal.m4 configure
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am2
-rw-r--r--Makefile.in5
-rw-r--r--README4
-rw-r--r--aclocal.m4158
-rw-r--r--buildrun.cxx29
-rwxr-xr-xconfigure239
-rw-r--r--configure.ac11
-rw-r--r--doc/Makefile.in3
-rw-r--r--doc/SystemTap_Tapset_Reference/Makefile.in3
-rwxr-xr-xdtrace58
-rw-r--r--grapher/CairoWidget.cxx42
-rw-r--r--grapher/CairoWidget.hxx42
-rw-r--r--grapher/GraphData.hxx44
-rw-r--r--grapher/GraphWidget.cxx323
-rw-r--r--grapher/GraphWidget.hxx62
-rw-r--r--grapher/Makefile.am7
-rw-r--r--grapher/Makefile.in489
-rw-r--r--grapher/grapher.cxx127
-rw-r--r--main.cxx30
-rw-r--r--runtime/print.c28
-rw-r--r--runtime/syscall.h25
-rw-r--r--runtime/unwind.c2
-rw-r--r--runtime/unwind/unwind.h4
-rw-r--r--runtime/vsprintf.c355
-rw-r--r--stap.1.in9
-rw-r--r--tapset/utrace.stp24
-rw-r--r--testsuite/systemtap.base/static_uprobes.exp1
-rw-r--r--testsuite/systemtap.base/utrace_syscall_args.c67
-rw-r--r--testsuite/systemtap.base/utrace_syscall_args.exp82
-rw-r--r--testsuite/systemtap.base/utrace_syscall_args.stp366
-rw-r--r--testsuite/systemtap.examples/general/grapher.stp32
-rw-r--r--testsuite/systemtap.examples/index.html3
-rw-r--r--testsuite/systemtap.examples/index.txt7
-rw-r--r--testsuite/systemtap.examples/keyword-index.html23
-rw-r--r--testsuite/systemtap.examples/keyword-index.txt34
-rw-r--r--testsuite/systemtap.examples/network/dropwatch.meta13
-rwxr-xr-xtestsuite/systemtap.examples/network/dropwatch.stp30
-rw-r--r--translate.cxx30
39 files changed, 2699 insertions, 115 deletions
diff --git a/.gitignore b/.gitignore
index cd63142e..5869f401 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@ config.status
.deps
loc2c-test
run-stap
+run-staprun
stamp-h1
stap
staprun
diff --git a/Makefile.am b/Makefile.am
index 1c14f8d5..a80b8ce8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -275,7 +275,7 @@ uninstall-local:
rm -rf $(DESTDIR)$(sysconfdir)/systemtap
# XXX: leaves behind man pages
-SUBDIRS = doc
+SUBDIRS = doc grapher
DIST_SUBDIRS = testsuite $(SUBDIRS)
check-local:
diff --git a/Makefile.in b/Makefile.in
index fdec204e..e2f30aa1 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -216,6 +216,8 @@ ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
+GRAPHER_CFLAGS = @GRAPHER_CFLAGS@
+GRAPHER_LIBS = @GRAPHER_LIBS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
@@ -241,6 +243,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@
PIECFLAGS = @PIECFLAGS@
PIECXXFLAGS = @PIECXXFLAGS@
PIELDFLAGS = @PIELDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
PROCFLAGS = @PROCFLAGS@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
@@ -382,7 +385,7 @@ EXAMPLE_SOURCE_DIR = $(srcdir)/testsuite/systemtap.examples
EXAMPLE_META_FILES = $(EXAMPLE_SOURCE_DIR)/*/*.meta
TEST_COV_DIR = coverage
# XXX: leaves behind man pages
-SUBDIRS = doc
+SUBDIRS = doc grapher
DIST_SUBDIRS = testsuite $(SUBDIRS)
# Any extra flags, such as:
diff --git a/README b/README
index 7c1ab412..ac6f0a97 100644
--- a/README
+++ b/README
@@ -106,3 +106,7 @@ Building a kernel.org kernel:
- Or else, if you wish to install the kernel build/debuginfo data into
a place where systemtap will find it without the "-r" option:
% ln -s /path/to/kernel/build/tree /lib/modules/RELEASE/build
+
+- Instead of using the "-r" option, you can also use the environment
+ variable SYSTEMTAP_RELEASE to direct systemtap to the kernel data.
+
diff --git a/aclocal.m4 b/aclocal.m4
index 9d70920d..b64e85be 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -16,6 +16,164 @@ m4_if(m4_PACKAGE_VERSION, [2.61],,
You have another version of autoconf. If you want to use that,
you should regenerate the build system entirely.], [63])])
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+#
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+#
+# Similar to PKG_CHECK_MODULES, make sure that the first instance of
+# this or PKG_CHECK_MODULES is called, or make sure to call
+# PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_ifval([$2], [$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$PKG_CONFIG"; then
+ if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ else
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+ [pkg_failed=yes])
+ fi
+else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ ifelse([$4], , [AC_MSG_ERROR(dnl
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT
+])],
+ [AC_MSG_RESULT([no])
+ $4])
+elif test $pkg_failed = untried; then
+ ifelse([$4], , [AC_MSG_FAILURE(dnl
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
+ [$4])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ ifelse([$3], , :, [$3])
+fi[]dnl
+])# PKG_CHECK_MODULES
+
# Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
diff --git a/buildrun.cxx b/buildrun.cxx
index 3c0d8f4b..5055f7fe 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -388,7 +388,6 @@ make_tracequery(systemtap_session& s, string& name, const vector<string>& extra_
// create our source file
string source(dir + "/tracequery.c");
ofstream osrc(source.c_str());
- osrc << "#include <linux/module.h>" << endl;
osrc << "#ifdef CONFIG_TRACEPOINTS" << endl;
osrc << "#include <linux/tracepoint.h>" << endl;
@@ -402,6 +401,10 @@ make_tracequery(systemtap_session& s, string& name, const vector<string>& extra_
osrc << "#define DEFINE_TRACE(name, proto, args) \\" << endl;
osrc << " DECLARE_TRACE(name, TPPROTO(proto), TPARGS(args))" << endl;
+ // some headers may have been pulled in already indirectly, so we need this
+ // to ensure that they still use our definition
+ osrc << "#define TRACE_HEADER_MULTI_READ 1" << endl;
+
// PR9993: Add extra headers to work around undeclared types in individual
// include/trace/foo.h files
for (unsigned z=0; z<extra_headers.size(); z++)
@@ -409,32 +412,38 @@ make_tracequery(systemtap_session& s, string& name, const vector<string>& extra_
// dynamically pull in all tracepoint headers from include/trace/
glob_t trace_glob;
- string globs[2] = { "/include/trace/*.h", "/source/include/trace/*.h" };
- for (unsigned z=0; z<2; z++)
+ string globs[] = {
+ "/include/trace/*.h",
+ "/include/trace/events/*.h",
+ "/source/include/trace/*.h",
+ "/source/include/trace/events/*.h",
+ };
+ for (unsigned z = 0; z < sizeof(globs) / sizeof(globs[0]); z++)
{
string glob_str(s.kernel_build_tree + globs[z]);
glob(glob_str.c_str(), 0, NULL, &trace_glob);
for (unsigned i = 0; i < trace_glob.gl_pathc; ++i)
{
- string header(basename(trace_glob.gl_pathv[i]));
+ string header(trace_glob.gl_pathv[i]);
+ size_t root_pos = header.rfind("/include/");
+ assert(root_pos != string::npos);
+ header.erase(0, root_pos + 9);
// filter out a few known "internal-only" headers
- if (header == "trace_events.h")
+ if (header.find("/ftrace.h") != string::npos)
+ continue;
+ if (header.find("/trace_events.h") != string::npos)
continue;
if (header.find("_event_types.h") != string::npos)
continue;
- osrc << "#include <trace/" << header << ">" << endl;
+ osrc << "#include <" << header << ">" << endl;
}
globfree(&trace_glob);
}
// finish up the module source
osrc << "#endif /* CONFIG_TRACEPOINTS */" << endl;
- osrc << "int init_module(void) { return 0; }" << endl;
- osrc << "void cleanup_module(void) {}" << endl;
- osrc << "MODULE_DESCRIPTION(\"tracepoint query\");" << endl;
- osrc << "MODULE_LICENSE(\"GPL\");" << endl;
osrc.close();
// make the module
diff --git a/configure b/configure
index 09103bb5..a9887761 100755
--- a/configure
+++ b/configure
@@ -728,6 +728,11 @@ BUILD_SERVER_TRUE
BUILD_SERVER_FALSE
HAVE_NSS_TRUE
HAVE_NSS_FALSE
+PKG_CONFIG
+GRAPHER_CFLAGS
+GRAPHER_LIBS
+BUILD_GRAPHER_TRUE
+BUILD_GRAPHER_FALSE
BUILD_ELFUTILS_TRUE
BUILD_ELFUTILS_FALSE
elfutils_abs_srcdir
@@ -751,6 +756,9 @@ CXX
CXXFLAGS
CCC
CPP
+PKG_CONFIG
+GRAPHER_CFLAGS
+GRAPHER_LIBS
CXXCPP'
ac_subdirs_all='testsuite'
@@ -1351,6 +1359,8 @@ Optional Features:
if xmlto etc. found and other documentation built).
--enable-server enable building of stap-server/client (default on if
nss etc. found).
+ --enable-grapher enable building of grapher (default on if gtkmm is
+ found).
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@@ -1369,6 +1379,11 @@ Some influential environment variables:
CXX C++ compiler command
CXXFLAGS C++ compiler flags
CPP C preprocessor
+ PKG_CONFIG path to pkg-config utility
+ GRAPHER_CFLAGS
+ C compiler flags for GRAPHER, overriding pkg-config
+ GRAPHER_LIBS
+ linker flags for GRAPHER, overriding pkg-config
CXXCPP C++ preprocessor
Use these variables to override the choices made by `configure' or to help
@@ -6938,6 +6953,213 @@ else
fi
+# Check whether --enable-grapher was given.
+if test "${enable_grapher+set}" = set; then
+ enableval=$enable_grapher; enable_grapher=$enableval
+else
+ enable_grapher="check"
+fi
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5
+echo "${ECHO_T}$PKG_CONFIG" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+ { echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5
+echo "${ECHO_T}$ac_pt_PKG_CONFIG" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+ PKG_CONFIG=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=0.9.0
+ { echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5
+echo $ECHO_N "checking pkg-config is at least version $_pkg_min_version... $ECHO_C" >&6; }
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ PKG_CONFIG=""
+ fi
+
+fi
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for GRAPHER" >&5
+echo $ECHO_N "checking for GRAPHER... $ECHO_C" >&6; }
+
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GRAPHER_CFLAGS"; then
+ pkg_cv_GRAPHER_CFLAGS="$GRAPHER_CFLAGS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.8.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.8.0") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GRAPHER_CFLAGS=`$PKG_CONFIG --cflags "gtkmm-2.4 >= 2.8.0" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GRAPHER_LIBS"; then
+ pkg_cv_GRAPHER_LIBS="$GRAPHER_LIBS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.8.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.8.0") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GRAPHER_LIBS=`$PKG_CONFIG --libs "gtkmm-2.4 >= 2.8.0" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ GRAPHER_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.8.0"`
+ else
+ GRAPHER_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.8.0"`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$GRAPHER_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ have_gtkmm=no
+elif test $pkg_failed = untried; then
+ have_gtkmm=no
+else
+ GRAPHER_CFLAGS=$pkg_cv_GRAPHER_CFLAGS
+ GRAPHER_LIBS=$pkg_cv_GRAPHER_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ have_gtkmm=yes
+fi
+ if test "x${have_gtkmm}" == "xyes" -a x"$enable_grapher" != "xno"; then
+ BUILD_GRAPHER_TRUE=
+ BUILD_GRAPHER_FALSE='#'
+else
+ BUILD_GRAPHER_TRUE='#'
+ BUILD_GRAPHER_FALSE=
+fi
+
+
build_elfutils=no
# Check whether --with-elfutils was given.
@@ -7876,7 +8098,7 @@ _ACEOF
ac_config_headers="$ac_config_headers config.h:config.in"
-ac_config_files="$ac_config_files Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile stap.1 stapprobes.3stap stapfuncs.3stap stapvars.3stap stapex.3stap staprun.8 stap-server.8 man/stapprobes.iosched.3stap man/stapprobes.netdev.3stap man/stapprobes.nfs.3stap man/stapprobes.nfsd.3stap man/stapprobes.pagefault.3stap man/stapprobes.kprocess.3stap man/stapprobes.rpc.3stap man/stapprobes.scsi.3stap man/stapprobes.signal.3stap man/stapprobes.socket.3stap man/stapprobes.tcp.3stap man/stapprobes.udp.3stap initscript/systemtap"
+ac_config_files="$ac_config_files Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile grapher/Makefile stap.1 stapprobes.3stap stapfuncs.3stap stapvars.3stap stapex.3stap staprun.8 stap-server.8 man/stapprobes.iosched.3stap man/stapprobes.netdev.3stap man/stapprobes.nfs.3stap man/stapprobes.nfsd.3stap man/stapprobes.pagefault.3stap man/stapprobes.kprocess.3stap man/stapprobes.rpc.3stap man/stapprobes.scsi.3stap man/stapprobes.signal.3stap man/stapprobes.socket.3stap man/stapprobes.tcp.3stap man/stapprobes.udp.3stap initscript/systemtap"
subdirs="$subdirs testsuite"
@@ -8050,6 +8272,13 @@ echo "$as_me: error: conditional \"HAVE_NSS\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
+if test -z "${BUILD_GRAPHER_TRUE}" && test -z "${BUILD_GRAPHER_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"BUILD_GRAPHER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"BUILD_GRAPHER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
if test -z "${BUILD_ELFUTILS_TRUE}" && test -z "${BUILD_ELFUTILS_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"BUILD_ELFUTILS\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
@@ -8529,6 +8758,7 @@ do
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
"doc/SystemTap_Tapset_Reference/Makefile") CONFIG_FILES="$CONFIG_FILES doc/SystemTap_Tapset_Reference/Makefile" ;;
+ "grapher/Makefile") CONFIG_FILES="$CONFIG_FILES grapher/Makefile" ;;
"stap.1") CONFIG_FILES="$CONFIG_FILES stap.1" ;;
"stapprobes.3stap") CONFIG_FILES="$CONFIG_FILES stapprobes.3stap" ;;
"stapfuncs.3stap") CONFIG_FILES="$CONFIG_FILES stapfuncs.3stap" ;;
@@ -8768,6 +8998,11 @@ BUILD_SERVER_TRUE!$BUILD_SERVER_TRUE$ac_delim
BUILD_SERVER_FALSE!$BUILD_SERVER_FALSE$ac_delim
HAVE_NSS_TRUE!$HAVE_NSS_TRUE$ac_delim
HAVE_NSS_FALSE!$HAVE_NSS_FALSE$ac_delim
+PKG_CONFIG!$PKG_CONFIG$ac_delim
+GRAPHER_CFLAGS!$GRAPHER_CFLAGS$ac_delim
+GRAPHER_LIBS!$GRAPHER_LIBS$ac_delim
+BUILD_GRAPHER_TRUE!$BUILD_GRAPHER_TRUE$ac_delim
+BUILD_GRAPHER_FALSE!$BUILD_GRAPHER_FALSE$ac_delim
BUILD_ELFUTILS_TRUE!$BUILD_ELFUTILS_TRUE$ac_delim
BUILD_ELFUTILS_FALSE!$BUILD_ELFUTILS_FALSE$ac_delim
elfutils_abs_srcdir!$elfutils_abs_srcdir$ac_delim
@@ -8780,7 +9015,7 @@ LIBOBJS!$LIBOBJS$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF
- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 27; then
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 32; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
diff --git a/configure.ac b/configure.ac
index 1ed44007..36e87e3d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -256,6 +256,15 @@ fi
AM_CONDITIONAL([BUILD_SERVER], [test "x${have_nss_includes}${have_nss_libs}" == "xyesyes" -a "$enable_server" != "no"])
AM_CONDITIONAL([HAVE_NSS], [test "x${have_nss_includes}${have_nss_libs}" == "xyesyes"])
+dnl Handle the optional grapher
+AC_ARG_ENABLE([grapher],
+ AS_HELP_STRING([--enable-grapher],
+ [enable building of grapher (default on if gtkmm is found).]),
+ [enable_grapher=$enableval],
+ [enable_grapher="check"])
+PKG_CHECK_MODULES([GRAPHER], [gtkmm-2.4 >= 2.8.0],have_gtkmm=yes,have_gtkmm=no)
+AM_CONDITIONAL([BUILD_GRAPHER], [test "x${have_gtkmm}" == "xyes" -a x"$enable_grapher" != "xno"])
+
dnl Handle elfutils. If '--with-elfutils=DIR' wasn't specified, used
dnl the system's elfutils.
build_elfutils=no
@@ -359,7 +368,7 @@ dnl Don't use this directly (when not given it is set to NONE).
AC_DEFINE_UNQUOTED(STAP_PREFIX, "$prefix", [configure prefix location])
AC_CONFIG_HEADERS([config.h:config.in])
-AC_CONFIG_FILES(Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile stap.1 stapprobes.3stap stapfuncs.3stap stapvars.3stap stapex.3stap staprun.8 stap-server.8 man/stapprobes.iosched.3stap man/stapprobes.netdev.3stap man/stapprobes.nfs.3stap man/stapprobes.nfsd.3stap man/stapprobes.pagefault.3stap man/stapprobes.kprocess.3stap man/stapprobes.rpc.3stap man/stapprobes.scsi.3stap man/stapprobes.signal.3stap man/stapprobes.socket.3stap man/stapprobes.tcp.3stap man/stapprobes.udp.3stap initscript/systemtap)
+AC_CONFIG_FILES(Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile grapher/Makefile stap.1 stapprobes.3stap stapfuncs.3stap stapvars.3stap stapex.3stap staprun.8 stap-server.8 man/stapprobes.iosched.3stap man/stapprobes.netdev.3stap man/stapprobes.nfs.3stap man/stapprobes.nfsd.3stap man/stapprobes.pagefault.3stap man/stapprobes.kprocess.3stap man/stapprobes.rpc.3stap man/stapprobes.scsi.3stap man/stapprobes.signal.3stap man/stapprobes.socket.3stap man/stapprobes.tcp.3stap man/stapprobes.udp.3stap initscript/systemtap)
AC_CONFIG_SUBDIRS(testsuite)
AC_CONFIG_FILES([run-stap], [chmod +x run-stap])
AC_CONFIG_FILES([run-staprun], [chmod +x run-staprun])
diff --git a/doc/Makefile.in b/doc/Makefile.in
index eafd7ca7..8f110eb7 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -79,6 +79,8 @@ ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
+GRAPHER_CFLAGS = @GRAPHER_CFLAGS@
+GRAPHER_LIBS = @GRAPHER_LIBS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
@@ -104,6 +106,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@
PIECFLAGS = @PIECFLAGS@
PIECXXFLAGS = @PIECXXFLAGS@
PIELDFLAGS = @PIELDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
PROCFLAGS = @PROCFLAGS@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
diff --git a/doc/SystemTap_Tapset_Reference/Makefile.in b/doc/SystemTap_Tapset_Reference/Makefile.in
index 30ca4b17..d569c298 100644
--- a/doc/SystemTap_Tapset_Reference/Makefile.in
+++ b/doc/SystemTap_Tapset_Reference/Makefile.in
@@ -82,6 +82,8 @@ ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
+GRAPHER_CFLAGS = @GRAPHER_CFLAGS@
+GRAPHER_LIBS = @GRAPHER_LIBS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
@@ -107,6 +109,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@
PIECFLAGS = @PIECFLAGS@
PIECXXFLAGS = @PIECXXFLAGS@
PIELDFLAGS = @PIELDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
PROCFLAGS = @PROCFLAGS@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
diff --git a/dtrace b/dtrace
index ca95b678..a2b495b2 100755
--- a/dtrace
+++ b/dtrace
@@ -17,12 +17,11 @@ from subprocess import call
from tempfile import mkstemp
class provider:
- arglist = dict()
def open(self, provider, header):
have_provider = False
self.f = open(provider)
self.h = open(header,mode='w')
- self.h.write("// Generated by the Systemtap dtrace wrapper\n")
+ self.h.write("/* Generated by the Systemtap dtrace wrapper */\n")
self.h.write("\n#include <sys/sdt.h>\n\n")
in_comment = False
while (True):
@@ -49,7 +48,6 @@ class provider:
new_args = ""
i = 0
c = 0
- self.arglist[this_probe] = ""
while (i < len(args)):
if (args[i:i+1] == ","):
new_args = ('%s%s' % (new_args, args[i]))
@@ -57,41 +55,24 @@ class provider:
else:
new_args = new_args + args[i]
i += 1
- if (len(new_args) > 0):
- self.arglist[this_probe] = ('%s arg%d' % (new_args, c))
if (len(new_args) == 0):
- self.h.write ('#define %s() STAP_PROBE(provider,%s)\n' % (this_probe_canon, this_probe))
- elif (c == 0):
- self.h.write ('#define %s(arg1) STAP_PROBE%d(provider,%s,arg1)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 1):
- self.h.write ('#define %s(arg1,arg2) STAP_PROBE%d(provider,%s,arg1,arg2)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 2):
- self.h.write ('#define %s(arg1,arg2,arg3) STAP_PROBE%d(provider,%s,arg1,arg2,arg3)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 3):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 4):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 5):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5,arg6) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5,arg6)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 6):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5,arg6,arg7) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 7):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 8):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 9):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\n' % (this_probe_canon, c+1, this_probe))
+ c = 0
+ stap_str = "STAP_PROBE(provider,%s" % (this_probe)
+ else:
+ c += 1
+ stap_str = "STAP_PROBE%d(provider,%s" % (c,this_probe)
+ define_str = "#define %s(" % (this_probe_canon)
+ i = 1
+ while (i <= c):
+ if (i != 1):
+ define_str += ","
+ define_str = define_str + "arg%s" % (i);
+ stap_str = stap_str + ",arg%s" % (i);
+ i += 1
+ self.h.write ('/* %s (%s) */\n' % (this_probe_canon,new_args))
self.h.write ('#define %s_ENABLED() 1\n' % this_probe_canon)
-
- def get(self, arg):
- print arg
- if (arg in self.arglist):
- return self.arglist[arg]
- else:
- return ""
-########################################################################
-# main
-########################################################################
+ self.h.write (define_str + ") \\\n")
+ self.h.write (stap_str + ")\n\n")
def usage ():
print "Usage " + sys.argv[0] + " [-h | -G] -s File.d -o File {Files}"
@@ -107,6 +88,11 @@ def open_file (arg):
sys.exit(1)
return file
+
+########################################################################
+# main
+########################################################################
+
if (len (sys.argv) < 2):
usage()
diff --git a/grapher/CairoWidget.cxx b/grapher/CairoWidget.cxx
new file mode 100644
index 00000000..86498a4f
--- /dev/null
+++ b/grapher/CairoWidget.cxx
@@ -0,0 +1,42 @@
+#include "CairoWidget.hxx"
+
+#include <math.h>
+
+namespace systemtap
+{
+ void CairoPlayButton::draw(Cairo::RefPtr<Cairo::Context> cr)
+ {
+ if (!_visible)
+ return;
+ cr->save();
+ cr->set_line_width(1.0);
+ // square with rounded corners
+ cr->move_to(_x0, _y0 + _radius);
+ cr->arc(_x0 + _radius, _y0 + _radius, _radius, M_PI, -M_PI_2);
+ cr->line_to(_x0 + _size - _radius, _y0);
+ cr->arc(_x0 + _size - _radius, _y0 + _radius, _radius, -M_PI_2, 0.0);
+ cr->line_to(_x0 + _size, _y0 + _size - _radius);
+ cr->arc(_x0 + _size - _radius, _y0 + _size - _radius, _radius, 0.0, M_PI_2);
+ cr->line_to(_x0 + _radius, _y0 + _size);
+ cr->arc(_x0 + _radius, _y0 + _size - _radius, _radius, M_PI_2, M_PI);
+ cr->close_path();
+ //cr->rectangle(_x0, _y0, 50.0, 50.0);
+ cr->set_source_rgba(1.0, 1.0, 1.0, .8);
+ cr->stroke();
+ // play equalateral triangle
+ cr->move_to(_x0 + .25 * _size, _y0 + (.5 - 1.0 / (sqrt(3.0) * 2.0)) * _size);
+ cr->line_to(_x0 + .75 * _size, _y0 + .5 * _size);
+ cr->line_to(_x0 + .25 * _size, _y0 + (.5 + 1.0 / (sqrt(3.0) * 2.0)) * _size);
+ cr->close_path();
+ cr->fill();
+ cr->restore();
+ }
+
+ bool CairoPlayButton::containsPoint(double x, double y)
+ {
+ if (x >= _x0 && (x < (_x0 + 50.0)) && (y >= _y0) && (y < (_y0 + 50)))
+ return true;
+ else
+ return false;
+ }
+}
diff --git a/grapher/CairoWidget.hxx b/grapher/CairoWidget.hxx
new file mode 100644
index 00000000..077a4c7a
--- /dev/null
+++ b/grapher/CairoWidget.hxx
@@ -0,0 +1,42 @@
+#ifndef SYSTEMTAP_CAIROWIDGET_H
+#define SYSTEMTAP_CAIROWIDGET_H 1
+
+#include <cairomm/context.h>
+namespace systemtap
+{
+ class CairoWidget
+ {
+ public:
+ CairoWidget(bool visible = false)
+ : _visible(visible), _size(50.0), _radius(5)
+ {}
+ bool isVisible() const { return _visible; }
+ void setVisible(bool visible) { _visible = visible; }
+ void getOrigin(double &x, double &y) const
+ {
+ x = _x0;
+ y = _y0;
+ }
+ void setOrigin(double x, double y)
+ {
+ _x0 = x;
+ _y0 = y;
+ }
+ virtual void draw(Cairo::RefPtr<Cairo::Context> cr) = 0;
+ virtual bool containsPoint(double x, double y) { return false; }
+ protected:
+ bool _visible;
+ double _x0;
+ double _y0;
+ double _size;
+ double _radius;
+ };
+
+ class CairoPlayButton : public CairoWidget
+ {
+ public:
+ virtual void draw(Cairo::RefPtr<Cairo::Context> cr);
+ virtual bool containsPoint(double x, double y);
+ };
+}
+#endif
diff --git a/grapher/GraphData.hxx b/grapher/GraphData.hxx
new file mode 100644
index 00000000..0f3b0b31
--- /dev/null
+++ b/grapher/GraphData.hxx
@@ -0,0 +1,44 @@
+#ifndef SYSTEMTAP_GRAPHDATA_HXX
+#define SYSTEMTAP_GRAPHDATA_HXX 1
+
+#include <utility>
+#include <vector>
+
+namespace systemtap
+{
+ struct GraphData
+ {
+ public:
+ enum Style
+ { BAR,
+ DOT
+ };
+ GraphData() : scale(1.0), style(BAR)
+ {
+ color[0] = 0.0; color[1] = 1.0; color[2] = 0.0;
+ }
+ typedef std::pair<double, double> Datum;
+ typedef std::vector<Datum> List;
+ // size of grid square at "normal" viewing
+ double scale;
+ double color[3];
+ Style style;
+ List data;
+ struct Compare
+ {
+ bool operator() (const Datum& lhs, const Datum& rhs) const
+ {
+ return lhs.first < rhs.first;
+ }
+ bool operator() (double lhs, const Datum& rhs) const
+ {
+ return lhs < rhs.first;
+ }
+ bool operator() (const Datum& lhs, double rhs) const
+ {
+ return lhs.first < rhs;
+ }
+ };
+ };
+}
+#endif
diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx
new file mode 100644
index 00000000..5186c471
--- /dev/null
+++ b/grapher/GraphWidget.cxx
@@ -0,0 +1,323 @@
+#include <algorithm>
+#include <ctime>
+#include <math.h>
+#include <sstream>
+#include <iomanip>
+#include <cairomm/context.h>
+#include "GraphWidget.hxx"
+#include "CairoWidget.hxx"
+
+namespace systemtap
+{
+ GraphWidget::GraphWidget()
+ : _left(0.0), _right(1.0), _top(1.0), _bottom(0.0), _lineWidth(10),
+ _autoScaling(true), _autoScrolling(true), _zoomFactor(1.0),
+ _trackingDrag(false), _playButton(new CairoPlayButton)
+ {
+ add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK
+ | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK);
+ Glib::signal_timeout()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_timeout), 1000);
+ signal_expose_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_expose_event), false);
+ signal_button_press_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_button_press_event),
+ false);
+ signal_button_release_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_button_release_event),
+ false);
+ signal_motion_notify_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_motion_notify_event),
+ false);
+ signal_scroll_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_scroll_event), false);
+ }
+
+ void GraphWidget::getExtents(double& left, double& right, double& top,
+ double& bottom) const
+ {
+ left = _left;
+ right = _right;
+ top = _top;
+ bottom = _bottom;
+ }
+
+ void GraphWidget::setExtents(double left, double right, double top,
+ double bottom)
+ {
+ _left = left;
+ _right = right;
+ _top = top;
+ _bottom = bottom;
+
+ }
+ GraphWidget::~GraphWidget()
+ {
+ }
+
+ void GraphWidget::addGraphData(std::tr1::shared_ptr<GraphData> data)
+ {
+ _datasets.push_back(data);
+ }
+
+ bool GraphWidget::on_expose_event(GdkEventExpose* event)
+ {
+ // This is where we draw on the window
+ Glib::RefPtr<Gdk::Window> window = get_window();
+ if(!window)
+ return true;
+
+ Gtk::Allocation allocation = get_allocation();
+
+ const int graphWidth = allocation.get_width();
+ const int graphHeight = allocation.get_height();
+ const int width = graphWidth - 20;
+ const int height = graphHeight - 20;
+
+ Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
+ if(event && !_autoScaling)
+ {
+ // clip to the area indicated by the expose event so that we only
+ // redraw the portion of the window that needs to be redrawn
+ cr->rectangle(event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cr->clip();
+ }
+ if (_autoScaling)
+ {
+ // line separation
+ int linesPossible = width / (_lineWidth + 2);
+ // Find latest time.
+ double latestTime = 0;
+ for (DatasetList::iterator ditr = _datasets.begin(),
+ de = _datasets.end();
+ ditr != de;
+ ++ditr)
+ {
+ if (!(*ditr)->data.empty())
+ {
+ double lastDataTime = (*ditr)->data.back().first;
+ if (lastDataTime > latestTime)
+ latestTime = lastDataTime;
+ }
+ }
+ double minDiff = 0.0;
+ double maxTotal = 0.0;
+ for (DatasetList::iterator ditr = _datasets.begin(),
+ de = _datasets.end();
+ ditr != de;
+ ++ditr)
+ {
+ GraphData::List& gdata = (*ditr)->data;
+ if (gdata.size() <= 1)
+ continue;
+ double totalDiff = 0.0;
+ for (GraphData::List::reverse_iterator ritr = gdata.rbegin(),
+ re = gdata.rend();
+ ritr + 1 != gdata.rend();
+ ritr++)
+ {
+ double timeDiff = ritr->first - (ritr + 1)->first;
+ if (timeDiff < minDiff || (timeDiff != 0 && minDiff == 0))
+ minDiff = timeDiff;
+ if (minDiff != 0
+ && (totalDiff + timeDiff) / minDiff > linesPossible)
+ break;
+ totalDiff += timeDiff;
+ }
+ if (totalDiff > maxTotal)
+ maxTotal = totalDiff;
+ }
+ // Now we have a global scale.
+ _right = latestTime;
+ if (maxTotal != 0)
+ _left = latestTime - maxTotal;
+ else
+ _left = _right - 1.0;
+ }
+ cr->save();
+ double horizScale = _zoomFactor * width / ( _right - _left);
+ cr->translate(20.0, 0.0);
+ cr->set_line_width(_lineWidth);
+ cr->save();
+ cr->set_source_rgba(0.0, 0.0, 0.0, 1.0);
+ cr->paint();
+ cr->restore();
+
+ for (DatasetList::iterator itr = _datasets.begin(), e = _datasets.end();
+ itr != e;
+ ++itr)
+ {
+ cr->save();
+ cr->translate(0.0, height);
+ cr->scale(1.0, -1.0);
+ GraphData::List::iterator lower
+ = std::lower_bound((*itr)->data.begin(), (*itr)->data.end(), _left,
+ GraphData::Compare());
+ GraphData::List::iterator upper
+ = std::upper_bound((*itr)->data.begin(), (*itr)->data.end(), _right,
+ GraphData::Compare());
+ for (GraphData::List::iterator ditr = lower, de = upper;
+ ditr != de;
+ ++ditr)
+ {
+ cr->set_source_rgba((*itr)->color[0], (*itr)->color[1],
+ (*itr)->color[2], 1.0);
+ if ((*itr)->style == GraphData::BAR)
+ {
+ cr->move_to((ditr->first - _left) * horizScale, 0);
+ cr->line_to((ditr->first - _left) * horizScale,
+ ditr->second * height / (*itr)->scale);
+ cr->stroke();
+ }
+ else
+ {
+ cr->arc((ditr->first - _left) * horizScale,
+ ditr->second * height / (*itr)->scale,
+ _lineWidth / 2.0, 0.0, M_PI * 2.0);
+ cr->fill();
+ }
+ }
+ cr->restore();
+ }
+ cr->restore();
+ cr->save();
+ cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL,
+ Cairo::FONT_WEIGHT_BOLD);
+ cr->set_font_size(14.0);
+ cr->set_source_rgba(1.0, 1.0, 1.0, .8);
+
+ if (!_title.empty())
+ {
+ cr->move_to(20.0, 20.0);
+ cr->show_text(_title);
+ }
+ if (!_xAxisText.empty())
+ {
+ cr->move_to(10.0, graphHeight - 5);
+ cr->show_text(_xAxisText);
+ }
+ if (!_yAxisText.empty())
+ {
+ cr->save();
+ cr->translate(10.0, height - 10.0);
+ cr->rotate(-M_PI / 2.0);
+ cr->move_to(10.0, 0.0);
+ cr->show_text(_yAxisText);
+ cr->restore();
+ }
+ cr->restore();
+ // Draw axes
+ double diff = _right - _left;
+ double majorUnit = pow(10.0, floor(log(diff) / log(10.0)));
+ double startTime = floor(_left / majorUnit) * majorUnit;
+ cr->save();
+ cr->set_source_rgba(1.0, 1.0, 1.0, .9);
+ cr->set_line_cap(Cairo::LINE_CAP_BUTT);
+ cr->set_line_width(_lineWidth);
+ cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL,
+ Cairo::FONT_WEIGHT_NORMAL);
+ cr->set_font_size(10.0);
+ cr->move_to(20.0, 0.0);
+ cr->line_to(20.0, height);
+ cr->move_to(20.0, height);
+ cr->line_to(graphWidth, height);
+ cr->stroke();
+ std::vector<double> dash(1);
+ dash[0] = height / 10;
+ cr->set_dash(dash, 0);
+ for (double tickVal = startTime; tickVal < _right; tickVal += majorUnit)
+ {
+ cr->move_to((tickVal - _left) * horizScale + 20.0, graphHeight - 5);
+ std::ostringstream stream;
+ stream << std::fixed << std::setprecision(0) << tickVal;
+ cr->show_text(stream.str());
+ cr->move_to((tickVal - _left) * horizScale + 20.0, 0.0);
+ cr->line_to((tickVal - _left) * horizScale + 20.0, height);
+ cr->stroke();
+ }
+ cr->stroke();
+ cr->restore();
+
+ if (!_autoScrolling)
+ {
+ _playButton->setVisible(true);
+ _playButton->setOrigin(width / 2 - 25, .875 * height - 50);
+ _playButton->draw(cr);
+ }
+
+ return true;
+ }
+
+ bool GraphWidget::on_button_press_event(GdkEventButton* event)
+ {
+ if (!_autoScrolling && _playButton->containsPoint(event->x, event->y))
+ {
+ _autoScaling = true;
+ _autoScrolling = true;
+ queue_draw();
+ }
+ else
+ {
+ _trackingDrag = true;
+ _autoScaling = false;
+ _autoScrolling = false;
+ _dragOriginX = event->x;
+ _dragOriginY = event->y;
+ _dragOrigLeft = _left;
+ _dragOrigRight = _right;
+ }
+ return true;
+ }
+
+ bool GraphWidget::on_button_release_event(GdkEventButton* event)
+ {
+ _trackingDrag = false;
+ return true;
+ }
+
+ bool GraphWidget::on_motion_notify_event(GdkEventMotion* event)
+ {
+ Glib::RefPtr<Gdk::Window> win = get_window();
+ if(!win)
+ return true;
+ double x;
+ double y;
+ // XXX Hint
+ if (event->is_hint)
+ {
+ }
+ else
+ {
+ x = event->x;
+ y = event->y;
+ }
+ if (_trackingDrag)
+ {
+ Gtk::Allocation allocation = get_allocation();
+ const int width = allocation.get_width();
+ double motion = (x - _dragOriginX) / (double) width;
+ double increment = motion * (_dragOrigLeft - _dragOrigRight);
+ _left = _dragOrigLeft + increment;
+ _right = _dragOrigRight + increment;
+ queue_draw();
+ }
+ return true;
+ }
+
+ bool GraphWidget::on_scroll_event(GdkEventScroll* event)
+ {
+ if (event->direction == GDK_SCROLL_UP)
+ _zoomFactor += .1;
+ else if (event->direction == GDK_SCROLL_DOWN)
+ _zoomFactor -= .1;
+ queue_draw();
+ return true;
+ }
+
+ bool GraphWidget::on_timeout()
+ {
+ queue_draw();
+ return true;
+ }
+}
diff --git a/grapher/GraphWidget.hxx b/grapher/GraphWidget.hxx
new file mode 100644
index 00000000..46075b78
--- /dev/null
+++ b/grapher/GraphWidget.hxx
@@ -0,0 +1,62 @@
+#ifndef SYSTEMTAP_GRAPHWIDGET_H
+#define SYSTEMTAP_GRAPHWIDGET_H
+
+#include <string>
+#include <vector>
+#include <tr1/memory>
+
+#include <gtkmm/drawingarea.h>
+#include "GraphData.hxx"
+
+namespace systemtap
+{
+ class CairoPlayButton;
+
+ class GraphWidget : public Gtk::DrawingArea
+ {
+ public:
+ GraphWidget();
+ virtual ~GraphWidget();
+ void addGraphData(std::tr1::shared_ptr<GraphData> data);
+ void getExtents(double& left, double& right, double& top, double& bottom) const;
+ void setExtents(double left, double right, double top, double bottom);
+ double getLineWidth() { return _lineWidth; }
+ void setLineWidth(double lineWidth) { _lineWidth = lineWidth; }
+ bool getAutoScaling() const { return _autoScaling; }
+ void setAutoScaling(bool val) { _autoScaling = val; }
+ std::string getTitle() const { return _title; }
+ void setTitle(const std::string& title) { _title = title; }
+ std::string getXAxisText() const { return _xAxisText; }
+ void setXAxisText(const std::string& text) { _xAxisText = text; }
+ std::string getYAxisText() const { return _yAxisText; }
+ void setYAxisText(const std::string& text) { _yAxisText = text; }
+ protected:
+ //Override default signal handler:
+ virtual bool on_expose_event(GdkEventExpose* event);
+ virtual bool on_motion_notify_event(GdkEventMotion* event);
+ virtual bool on_button_press_event(GdkEventButton* event);
+ virtual bool on_button_release_event(GdkEventButton* event);
+ virtual bool on_scroll_event(GdkEventScroll* event);
+ bool on_timeout();
+ typedef std::vector<std::tr1::shared_ptr<GraphData> > DatasetList;
+ DatasetList _datasets;
+ double _left;
+ double _right;
+ double _top;
+ double _bottom;
+ double _lineWidth;
+ bool _autoScaling;
+ bool _autoScrolling;
+ double _zoomFactor;
+ bool _trackingDrag;
+ double _dragOriginX;
+ double _dragOriginY;
+ double _dragOrigLeft;
+ double _dragOrigRight;
+ std::string _title;
+ std::string _xAxisText;
+ std::string _yAxisText;
+ std::tr1::shared_ptr<CairoPlayButton> _playButton;
+ };
+}
+#endif // SYSTEMTAP_GRAPHWIDGET_H
diff --git a/grapher/Makefile.am b/grapher/Makefile.am
new file mode 100644
index 00000000..fdb52ef7
--- /dev/null
+++ b/grapher/Makefile.am
@@ -0,0 +1,7 @@
+if BUILD_GRAPHER
+bin_PROGRAMS = grapher
+
+grapher_CXXFLAGS = $(GRAPHER_CFLAGS)
+grapher_SOURCES = grapher.cxx GraphWidget.cxx CairoWidget.cxx
+grapher_LDADD = $(GRAPHER_LIBS)
+endif \ No newline at end of file
diff --git a/grapher/Makefile.in b/grapher/Makefile.in
new file mode 100644
index 00000000..e90d2b6d
--- /dev/null
+++ b/grapher/Makefile.in
@@ -0,0 +1,489 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+@BUILD_GRAPHER_TRUE@bin_PROGRAMS = grapher$(EXEEXT)
+subdir = grapher
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am__grapher_SOURCES_DIST = grapher.cxx GraphWidget.cxx CairoWidget.cxx
+@BUILD_GRAPHER_TRUE@am_grapher_OBJECTS = grapher-grapher.$(OBJEXT) \
+@BUILD_GRAPHER_TRUE@ grapher-GraphWidget.$(OBJEXT) \
+@BUILD_GRAPHER_TRUE@ grapher-CairoWidget.$(OBJEXT)
+grapher_OBJECTS = $(am_grapher_OBJECTS)
+am__DEPENDENCIES_1 =
+@BUILD_GRAPHER_TRUE@grapher_DEPENDENCIES = $(am__DEPENDENCIES_1)
+grapher_LINK = $(CXXLD) $(grapher_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+SOURCES = $(grapher_SOURCES)
+DIST_SOURCES = $(am__grapher_SOURCES_DIST)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATE = @DATE@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GRAPHER_CFLAGS = @GRAPHER_CFLAGS@
+GRAPHER_LIBS = @GRAPHER_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIECFLAGS = @PIECFLAGS@
+PIECXXFLAGS = @PIECXXFLAGS@
+PIELDFLAGS = @PIELDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PROCFLAGS = @PROCFLAGS@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+U = @U@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+elfutils_abs_srcdir = @elfutils_abs_srcdir@
+exec_prefix = @exec_prefix@
+have_dvips = @have_dvips@
+have_latex = @have_latex@
+have_latex2html = @have_latex2html@
+have_ps2pdf = @have_ps2pdf@
+have_xmlto = @have_xmlto@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nspr_CFLAGS = @nspr_CFLAGS@
+nss_CFLAGS = @nss_CFLAGS@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sqlite3_LIBS = @sqlite3_LIBS@
+srcdir = @srcdir@
+stap_LIBS = @stap_LIBS@
+staplog_CPPFLAGS = @staplog_CPPFLAGS@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@BUILD_GRAPHER_TRUE@grapher_CXXFLAGS = $(GRAPHER_CFLAGS)
+@BUILD_GRAPHER_TRUE@grapher_SOURCES = grapher.cxx GraphWidget.cxx CairoWidget.cxx
+@BUILD_GRAPHER_TRUE@grapher_LDADD = $(GRAPHER_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cxx .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu grapher/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu grapher/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+grapher$(EXEEXT): $(grapher_OBJECTS) $(grapher_DEPENDENCIES)
+ @rm -f grapher$(EXEEXT)
+ $(grapher_LINK) $(grapher_OBJECTS) $(grapher_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grapher-CairoWidget.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grapher-GraphWidget.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grapher-grapher.Po@am__quote@
+
+.cxx.o:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cxx.obj:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+grapher-grapher.o: grapher.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-grapher.o -MD -MP -MF $(DEPDIR)/grapher-grapher.Tpo -c -o grapher-grapher.o `test -f 'grapher.cxx' || echo '$(srcdir)/'`grapher.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-grapher.Tpo $(DEPDIR)/grapher-grapher.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='grapher.cxx' object='grapher-grapher.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-grapher.o `test -f 'grapher.cxx' || echo '$(srcdir)/'`grapher.cxx
+
+grapher-grapher.obj: grapher.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-grapher.obj -MD -MP -MF $(DEPDIR)/grapher-grapher.Tpo -c -o grapher-grapher.obj `if test -f 'grapher.cxx'; then $(CYGPATH_W) 'grapher.cxx'; else $(CYGPATH_W) '$(srcdir)/grapher.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-grapher.Tpo $(DEPDIR)/grapher-grapher.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='grapher.cxx' object='grapher-grapher.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-grapher.obj `if test -f 'grapher.cxx'; then $(CYGPATH_W) 'grapher.cxx'; else $(CYGPATH_W) '$(srcdir)/grapher.cxx'; fi`
+
+grapher-GraphWidget.o: GraphWidget.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-GraphWidget.o -MD -MP -MF $(DEPDIR)/grapher-GraphWidget.Tpo -c -o grapher-GraphWidget.o `test -f 'GraphWidget.cxx' || echo '$(srcdir)/'`GraphWidget.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-GraphWidget.Tpo $(DEPDIR)/grapher-GraphWidget.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='GraphWidget.cxx' object='grapher-GraphWidget.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-GraphWidget.o `test -f 'GraphWidget.cxx' || echo '$(srcdir)/'`GraphWidget.cxx
+
+grapher-GraphWidget.obj: GraphWidget.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-GraphWidget.obj -MD -MP -MF $(DEPDIR)/grapher-GraphWidget.Tpo -c -o grapher-GraphWidget.obj `if test -f 'GraphWidget.cxx'; then $(CYGPATH_W) 'GraphWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/GraphWidget.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-GraphWidget.Tpo $(DEPDIR)/grapher-GraphWidget.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='GraphWidget.cxx' object='grapher-GraphWidget.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-GraphWidget.obj `if test -f 'GraphWidget.cxx'; then $(CYGPATH_W) 'GraphWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/GraphWidget.cxx'; fi`
+
+grapher-CairoWidget.o: CairoWidget.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-CairoWidget.o -MD -MP -MF $(DEPDIR)/grapher-CairoWidget.Tpo -c -o grapher-CairoWidget.o `test -f 'CairoWidget.cxx' || echo '$(srcdir)/'`CairoWidget.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-CairoWidget.Tpo $(DEPDIR)/grapher-CairoWidget.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='CairoWidget.cxx' object='grapher-CairoWidget.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-CairoWidget.o `test -f 'CairoWidget.cxx' || echo '$(srcdir)/'`CairoWidget.cxx
+
+grapher-CairoWidget.obj: CairoWidget.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-CairoWidget.obj -MD -MP -MF $(DEPDIR)/grapher-CairoWidget.Tpo -c -o grapher-CairoWidget.obj `if test -f 'CairoWidget.cxx'; then $(CYGPATH_W) 'CairoWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/CairoWidget.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-CairoWidget.Tpo $(DEPDIR)/grapher-CairoWidget.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='CairoWidget.cxx' object='grapher-CairoWidget.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-CairoWidget.obj `if test -f 'CairoWidget.cxx'; then $(CYGPATH_W) 'CairoWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/CairoWidget.cxx'; fi`
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic ctags distclean distclean-compile \
+ distclean-generic distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-binPROGRAMS
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx
new file mode 100644
index 00000000..46182178
--- /dev/null
+++ b/grapher/grapher.cxx
@@ -0,0 +1,127 @@
+#include "GraphWidget.hxx"
+
+#include <cmath>
+#include <sstream>
+#include <string>
+#include <map>
+
+#include <gtkmm/main.h>
+#include <gtkmm/window.h>
+#include <unistd.h>
+#include <poll.h>
+
+using namespace systemtap;
+
+class StapParser
+{
+ Glib::ustring _buffer;
+ typedef std::map<std::string, std::tr1::shared_ptr<GraphData> > DataMap;
+ DataMap _dataSets;
+ Gtk::Window& _win;
+ GraphWidget& _widget;
+public:
+ StapParser(Gtk::Window& win,
+ GraphWidget& widget) : _win(win), _widget(widget) {}
+
+ bool ioCallback(Glib::IOCondition ioCondition)
+ {
+ if ((ioCondition & Glib::IO_IN) == 0)
+ return true;
+ char buf[256];
+ ssize_t bytes_read = 0;
+ bytes_read = read(0, buf, sizeof(buf) - 1);
+ if (bytes_read <= 0)
+ {
+ _win.hide();
+ return true;
+ }
+ buf[bytes_read] = '\0';
+ _buffer += buf;
+ Glib::ustring::size_type ret = Glib::ustring::npos;
+ while ((ret = _buffer.find('\n')) != Glib::ustring::npos)
+ {
+ Glib::ustring dataString(_buffer, 0, ret);
+ if (dataString[0] == '%')
+ {
+ size_t found;
+ if ((found = dataString.find("%Title:") == 0))
+ {
+ std::string title = dataString.substr(7);
+ _widget.setTitle(title);
+ }
+ else if ((found = dataString.find("%XAxisTitle:") == 0))
+ {
+ _widget.setXAxisText(dataString.substr(12));
+ }
+ else if ((found = dataString.find("%YAxisTitle:") == 0))
+ {
+ _widget.setYAxisText(dataString.substr(12));
+ }
+ else if ((found = dataString.find("%YMax:") == 0))
+ {
+ double ymax;
+ std::istringstream stream(dataString.substr(6));
+ stream >> ymax;
+ // _gdata->scale = ymax;
+ }
+ else if ((found = dataString.find("%DataSet:") == 0))
+ {
+ std::tr1::shared_ptr<GraphData> dataSet(new GraphData);
+ std::string setName;
+ int hexColor;
+ std::string style;
+ std::istringstream stream(dataString.substr(9));
+ stream >> setName >> dataSet->scale >> std::hex >> hexColor
+ >> style;
+ dataSet->color[0] = (hexColor >> 16) / 255.0;
+ dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0;
+ dataSet->color[2] = (hexColor & 0xff) / 255.0;
+ if (style == "dot")
+ dataSet->style = GraphData::DOT;
+ _dataSets.insert(std::make_pair(setName, dataSet));
+ _widget.addGraphData(dataSet);
+ }
+ }
+ else
+ {
+ std::string dataSet;
+ double time;
+ double data;
+ std::istringstream stream(dataString);
+ stream >> dataSet >> time >> data;
+ DataMap::iterator itr = _dataSets.find(dataSet);
+ if (itr != _dataSets.end())
+ itr->second->data.push_back(std::make_pair(time, data));
+ }
+ _buffer.erase(0, ret + 1);
+ }
+ return true;
+ }
+};
+
+int main(int argc, char** argv)
+{
+ Gtk::Main app(argc, argv);
+
+ Gtk::Window win;
+
+ win.set_title("Grapher");
+ win.set_default_size(600, 200);
+
+ GraphWidget w;
+
+ w.setExtents(0.0, 1.0, 5.0, 0.0);
+ w.setLineWidth(2);
+
+ StapParser stapParser(win, w);
+ Glib::signal_io().connect(sigc::mem_fun(stapParser,
+ &StapParser::ioCallback),
+ 0,
+ Glib::IO_IN);
+ win.add(w);
+ w.show();
+
+ Gtk::Main::run(win);
+
+ return 0;
+}
diff --git a/main.cxx b/main.cxx
index d367232d..73945242 100644
--- a/main.cxx
+++ b/main.cxx
@@ -438,6 +438,36 @@ main (int argc, char * const argv [])
if (s_tc != NULL)
s.tapset_compile_coverage = true;
+ const char* s_kr = getenv ("SYSTEMTAP_RELEASE");
+ if (s_kr != NULL) {
+ if (s_kr[0] == '/') // fully specified path
+ {
+ s.kernel_build_tree = s_kr;
+ string version_file_name = s.kernel_build_tree + "/include/config/kernel.release";
+ // The file include/config/kernel.release within the
+ // build tree is used to pull out the version information
+ ifstream version_file (version_file_name.c_str());
+ if (version_file.fail ())
+ {
+ cerr << "Missing " << version_file_name << endl;
+ exit(1);
+ }
+ else
+ {
+ char c;
+ s.kernel_release = "";
+ while (version_file.get(c) && c != '\n')
+ s.kernel_release.push_back(c);
+ }
+ }
+ else
+ {
+ s.kernel_release = string (s_kr);
+ s.kernel_build_tree = "/lib/modules/" + s.kernel_release + "/build";
+ }
+ }
+
+
while (true)
{
int long_opt;
diff --git a/runtime/print.c b/runtime/print.c
index 2c84d3c9..964a73c2 100644
--- a/runtime/print.c
+++ b/runtime/print.c
@@ -13,8 +13,8 @@
#include "string.h"
-#include "vsprintf.c"
#include "transport/transport.c"
+#include "vsprintf.c"
/** @file print.c
* Printing Functions.
@@ -173,34 +173,10 @@ static void _stp_print_binary (int num, ...)
*/
static void _stp_printf (const char *fmt, ...)
{
- int num;
va_list args;
- _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
- char *buf = pb->buf + pb->len;
- int size = STP_BUFFER_SIZE - pb->len;
-
va_start(args, fmt);
- num = _stp_vsnprintf(buf, size, fmt, args);
+ _stp_vsnprintf(NULL, 0, fmt, args);
va_end(args);
- if (unlikely(num >= size)) {
- /* overflowed the buffer */
- if (pb->len == 0) {
- /* A single print request exceeded the buffer size. */
- /* Should not be possible with Systemtap-generated code. */
- pb->len = STP_BUFFER_SIZE;
- _stp_print_flush();
- num = 0;
- } else {
- /* Need more space. Flush the previous contents */
- _stp_print_flush();
-
- /* try again */
- va_start(args, fmt);
- num = _stp_vsnprintf(pb->buf, STP_BUFFER_SIZE, fmt, args);
- va_end(args);
- }
- }
- pb->len += num;
}
/** Write a string into the print buffer.
diff --git a/runtime/syscall.h b/runtime/syscall.h
index 6d22ba83..5e538389 100644
--- a/runtime/syscall.h
+++ b/runtime/syscall.h
@@ -124,7 +124,7 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
static inline long
syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
- return regs->r15;
+ return regs->r15;
}
#endif
@@ -304,6 +304,17 @@ syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
_stp_error("invalid syscall arg request");
return;
}
+#ifdef CONFIG_PPC64
+ if (test_tsk_thread_flag(task, TIF_32BIT)) {
+ /*
+ * Zero-extend 32-bit argument values. The high bits are
+ * garbage ignored by the actual syscall dispatch.
+ */
+ while (n-- > 0)
+ args[n] = (u32) regs->gpr[3 + i + n];
+ return;
+ }
+#endif
memcpy(args, &regs->gpr[3 + i], n * sizeof(args[0]));
}
#endif
@@ -324,22 +335,22 @@ __ia64_syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
switch (i) {
case 0:
if (!n--) break;
- *args++ = *__ia64_fetch_register(i + 32, regs, cache);
+ *args++ = ia64_fetch_register(32, regs, cache);
case 1:
if (!n--) break;
- *args++ = *__ia64_fetch_register(i + 33, regs, cache);
+ *args++ = ia64_fetch_register(33, regs, cache);
case 2:
if (!n--) break;
- *args++ = *__ia64_fetch_register(i + 34, regs, cache);
+ *args++ = ia64_fetch_register(34, regs, cache);
case 3:
if (!n--) break;
- *args++ = *__ia64_fetch_register(i + 35, regs, cache);
+ *args++ = ia64_fetch_register(35, regs, cache);
case 4:
if (!n--) break;
- *args++ = *__ia64_fetch_register(i + 36, regs, cache);
+ *args++ = ia64_fetch_register(36, regs, cache);
case 5:
if (!n--) break;
- *args++ = *__ia64_fetch_register(i + 37, regs, cache);
+ *args++ = ia64_fetch_register(37, regs, cache);
}
}
#endif
diff --git a/runtime/unwind.c b/runtime/unwind.c
index f7b19def..41af72a7 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -345,7 +345,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, s
state->label = NULL;
return 1;
}
- if (state->stackDepth >= MAX_STACK_DEPTH)
+ if (state->stackDepth >= STP_MAX_STACK_DEPTH)
return 0;
state->stack[state->stackDepth++] = ptr.p8;
break;
diff --git a/runtime/unwind/unwind.h b/runtime/unwind/unwind.h
index 78a4bfef..3b6d0de0 100644
--- a/runtime/unwind/unwind.h
+++ b/runtime/unwind/unwind.h
@@ -23,7 +23,7 @@
#error "Unsupported dwarf unwind architecture"
#endif
-#define MAX_STACK_DEPTH 8
+#define STP_MAX_STACK_DEPTH 8
#ifndef BUILD_BUG_ON_ZERO
#define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1)
@@ -135,7 +135,7 @@ struct unwind_state {
unsigned stackDepth:8;
unsigned version:8;
const u8 *label;
- const u8 *stack[MAX_STACK_DEPTH];
+ const u8 *stack[STP_MAX_STACK_DEPTH];
};
static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
diff --git a/runtime/vsprintf.c b/runtime/vsprintf.c
index bd58d760..38ab0e2d 100644
--- a/runtime/vsprintf.c
+++ b/runtime/vsprintf.c
@@ -12,6 +12,9 @@
#ifndef _VSPRINTF_C_
#define _VSPRINTF_C_
+//forward declaration for _stp_vsnprintf
+static void * _stp_reserve_bytes (int);
+
static int skip_atoi(const char **s)
{
int i=0;
@@ -22,6 +25,10 @@ static int skip_atoi(const char **s)
enum print_flag {STP_ZEROPAD=1, STP_SIGN=2, STP_PLUS=4, STP_SPACE=8, STP_LEFT=16, STP_SPECIAL=32, STP_LARGE=64};
+/*
+ * Changes to number() will require a corresponding change to number_size below,
+ * to ensure proper buffer allocation for _stp_printf.
+ */
static char * number(char * buf, char * end, uint64_t num, int base, int size, int precision, enum print_flag type)
{
char c,sign,tmp[66];
@@ -115,6 +122,85 @@ static char * number(char * buf, char * end, uint64_t num, int base, int size, i
return buf;
}
+/*
+ * Calculates the number of bytes required to print the paramater num. A change to
+ * number() requires a corresponding change here, and vice versa, to ensure the
+ * calculated size and printed size match.
+ */
+static int number_size(uint64_t num, int base, int size, int precision, enum print_flag type) {
+ char c,sign,tmp[66];
+ const char *digits;
+ static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+ static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ int i, num_bytes = 0;
+
+ digits = (type & STP_LARGE) ? large_digits : small_digits;
+ if (type & STP_LEFT)
+ type &= ~STP_ZEROPAD;
+ if (base < 2 || base > 36)
+ return 0;
+ c = (type & STP_ZEROPAD) ? '0' : ' ';
+ sign = 0;
+ if (type & STP_SIGN) {
+ if ((int64_t) num < 0) {
+ sign = '-';
+ num = - (int64_t) num;
+ size--;
+ } else if (type & STP_PLUS) {
+ sign = '+';
+ size--;
+ } else if (type & STP_SPACE) {
+ sign = ' ';
+ size--;
+ }
+ }
+ if (type & STP_SPECIAL) {
+ if (base == 16)
+ size -= 2;
+ else if (base == 8)
+ size--;
+ }
+ i = 0;
+ if (num == 0)
+ tmp[i++]='0';
+ else while (num != 0)
+ tmp[i++] = digits[do_div(num,base)];
+ if (i > precision)
+ precision = i;
+ size -= precision;
+ if (!(type&(STP_ZEROPAD+STP_LEFT))) {
+ while(size-->0) {
+ num_bytes++;
+ }
+ }
+ if (sign) {
+ num_bytes++;
+ }
+ if (type & STP_SPECIAL) {
+ if (base==8) {
+ num_bytes++;
+ } else if (base==16) {
+ num_bytes+=2;
+ }
+ }
+ if (!(type & STP_LEFT)) {
+ while (size-- > 0) {
+ num_bytes++;
+ }
+ }
+ while (i < precision--) {
+ num_bytes++;
+ }
+ while (i-- > 0) {
+ num_bytes++;
+ }
+ while (size-- > 0) {
+ num_bytes++;
+ }
+ return num_bytes;
+
+}
+
static int check_binary_precision (int precision) {
/* precision can be unspecified (-1) or one of 1, 2, 4 or 8. */
switch (precision) {
@@ -148,9 +234,262 @@ static int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
if (unlikely((int) size < 0))
return 0;
- str = buf;
- end = buf + size - 1;
+ /*
+ * buf will be NULL when this function is called from _stp_printf.
+ * This branch calculates the exact size print buffer required for
+ * the string and allocates it with _stp_reserve_bytes. A change
+ * to this branch requires a corresponding change to the same
+ * section of code below.
+ */
+ if (buf == NULL) {
+ const char* fmt_copy = fmt;
+ int num_bytes = 0;
+ va_list args_copy;
+
+ va_copy(args_copy, args);
+
+ for (; *fmt_copy ; ++fmt_copy) {
+ if (*fmt_copy != '%') {
+ num_bytes++;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+ repeat_copy:
+ ++fmt_copy; /* this also skips first '%' */
+ switch (*fmt_copy) {
+ case '-': flags |= STP_LEFT; goto repeat_copy;
+ case '+': flags |= STP_PLUS; goto repeat_copy;
+ case ' ': flags |= STP_SPACE; goto repeat_copy;
+ case '#': flags |= STP_SPECIAL; goto repeat_copy;
+ case '0': flags |= STP_ZEROPAD; goto repeat_copy;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt_copy))
+ field_width = skip_atoi(&fmt_copy);
+ else if (*fmt_copy == '*') {
+ ++fmt_copy;
+ /* it's the next argument */
+ field_width = va_arg(args_copy, int);
+ if (field_width < 0) {
+ field_width = -field_width;
+ flags |= STP_LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt_copy == '.') {
+ ++fmt_copy;
+ if (isdigit(*fmt_copy))
+ precision = skip_atoi(&fmt_copy);
+ else if (*fmt_copy == '*') {
+ ++fmt_copy;
+ /* it's the next argument */
+ precision = va_arg(args_copy, int);
+ }
+ if (precision < 0)
+ precision = 0;
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt_copy == 'h' || *fmt_copy == 'l' || *fmt_copy == 'L') {
+ qualifier = *fmt_copy;
+ ++fmt_copy;
+ if (qualifier == 'l' && *fmt_copy == 'l') {
+ qualifier = 'L';
+ ++fmt_copy;
+ }
+ }
+
+ /* default base */
+ base = 10;
+
+ switch (*fmt_copy) {
+ case 'b':
+ num = va_arg(args_copy, int64_t);
+
+ /* Only certain values are valid for the precision. */
+ precision = check_binary_precision (precision);
+
+ /* Unspecified field width defaults to the specified
+ precision and vice versa. If neither is specified,
+ then both default to 8. */
+ if (field_width == -1) {
+ if (precision == -1) {
+ field_width = 8;
+ precision = 8;
+ }
+ else
+ field_width = precision;
+ }
+ else if (precision == -1) {
+ precision = check_binary_precision (field_width);
+ if (precision == -1)
+ precision = 8;
+ }
+
+ len = precision;
+ if (!(flags & STP_LEFT)) {
+ while (len < field_width--) {
+ num_bytes++;
+ }
+ }
+
+ num_bytes += precision;
+
+ while (len < field_width--)
+ num_bytes++;
+
+ continue;
+
+ case 's':
+ case 'M':
+ case 'm':
+ s = va_arg(args_copy, char *);
+ if ((unsigned long)s < PAGE_SIZE)
+ s = "<NULL>";
+
+ if (*fmt_copy == 's')
+ len = strnlen(s, precision);
+ else if (precision > 0)
+ len = precision;
+ else
+ len = 1;
+
+ if (!(flags & STP_LEFT)) {
+ while (len < field_width--) {
+ num_bytes++;
+ }
+ }
+ if (*fmt_copy == 'M') {
+ num_bytes += number_size((unsigned long) *(uint64_t *) s,
+ 16, field_width, len, flags);
+ }
+ else {
+ num_bytes += len;
+ }
+
+ while (len < field_width--) {
+ num_bytes++;
+ }
+ if(flags & STP_ZEROPAD) {
+ num_bytes++;
+ }
+ continue;
+ case 'X':
+ flags |= STP_LARGE;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= STP_SIGN;
+ case 'u':
+ break;
+
+ case 'p':
+ /* Note that %p takes an int64_t argument. */
+ len = 2*sizeof(void *) + 2;
+ flags |= STP_ZEROPAD;
+
+ if (field_width == -1)
+ field_width = len;
+
+ if (!(flags & STP_LEFT)) {
+ while (len < field_width) {
+ field_width--;
+ num_bytes++;
+ }
+ }
+
+ //account for "0x"
+ num_bytes+=2;
+ field_width-=2;
+
+ num_bytes += number_size((unsigned long) va_arg(args_copy, int64_t),
+ 16, field_width, field_width, flags);
+ continue;
+
+ case '%':
+ num_bytes++;
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'o':
+ base = 8;
+ break;
+
+ case 'c':
+ if (!(flags & STP_LEFT)) {
+ while (--field_width > 0) {
+ num_bytes++;
+ }
+ }
+ c = (unsigned char) va_arg(args_copy, int);
+ num_bytes++;
+ while (--field_width > 0) {
+ num_bytes++;
+ }
+ continue;
+
+ default:
+ num_bytes++;
+ if (*fmt_copy) {
+ num_bytes++;
+ } else {
+ --fmt_copy;
+ }
+ continue;
+ }
+
+ if (qualifier == 'L')
+ num = va_arg(args_copy, int64_t);
+ else if (qualifier == 'l') {
+ num = va_arg(args_copy, unsigned long);
+ if (flags & STP_SIGN)
+ num = (signed long) num;
+ } else if (qualifier == 'h') {
+ num = (unsigned short) va_arg(args_copy, int);
+ if (flags & STP_SIGN)
+ num = (signed short) num;
+ } else {
+ num = va_arg(args_copy, unsigned int);
+ if (flags & STP_SIGN)
+ num = (signed int) num;
+ }
+ num_bytes += number_size(num, base, field_width, precision, flags);
+ }
+
+ va_end(args_copy);
+
+ if (num_bytes == 0)
+ return 0;
+
+ //max print buffer size
+ if (num_bytes > STP_BUFFER_SIZE) {
+ num_bytes = STP_BUFFER_SIZE;
+ }
+
+ str = (char*)_stp_reserve_bytes(num_bytes);
+ size = num_bytes;
+ end = str + size - 1;
+
+ } else {
+ str = buf;
+ end = buf + size - 1;
+ }
+ /*
+ * Note that a change to code below requires a corresponding
+ * change in the code above to properly calculate the bytes
+ * required in the output buffer.
+ */
for (; *fmt ; ++fmt) {
if (*fmt != '%') {
if (str <= end)
@@ -433,11 +772,13 @@ static int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
field_width, precision, flags);
}
- if (likely(str <= end))
- *str = '\0';
- else if (size > 0)
- /* don't write out a null byte if the buf size is zero */
- *end = '\0';
+ if (buf != NULL) {
+ if (likely(str <= end))
+ *str = '\0';
+ else if (size > 0)
+ /* don't write out a null byte if the buf size is zero */
+ *end = '\0';
+ }
return str-buf;
}
diff --git a/stap.1.in b/stap.1.in
index c664962c..a5a8ab84 100644
--- a/stap.1.in
+++ b/stap.1.in
@@ -157,11 +157,16 @@ be used to override limit parameters described below.
Look for the systemtap runtime sources in the given directory.
.TP
.BI \-r " /DIR"
-Build for kernel in given build tree.
+Build for kernel in given build tree. Can also be set with the
+.I SYSTEMTAP_RELEASE
+environment variable.
.TP
.BI \-r " RELEASE"
Build for kernel in build tree
-.BR /lib/modules/RELEASE/build .
+.BR /lib/modules/RELEASE/build .
+Can also be set with the
+.I SYSTEMTAP_RELEASE
+environment variable.
.TP
.BI \-m " MODULE"
Use the given name for the generated kernel object module, instead
diff --git a/tapset/utrace.stp b/tapset/utrace.stp
index 00f427e6..0d26ed5f 100644
--- a/tapset/utrace.stp
+++ b/tapset/utrace.stp
@@ -1,20 +1,26 @@
/* utrace-only subset of register accessors */
-
%{
#include "syscall.h"
%}
-function _utrace_syscall_nr:long () %{
- THIS->__retvalue = syscall_get_nr(current, CONTEXT->regs); /* pure */
+function _utrace_syscall_nr:long () %{ /* pure */
+ THIS->__retvalue = syscall_get_nr(current, CONTEXT->regs);
%}
-function _utrace_syscall_arg:long (n:long) %{
- unsigned long arg = 0; /* pure */
- syscall_get_arguments(current, CONTEXT->regs, (int)THIS->n, 1, &arg);
- THIS->__retvalue = arg;
+function _utrace_syscall_arg:long (n:long) %{ /* pure */
+ unsigned long arg = 0;
+ syscall_get_arguments(current, CONTEXT->regs, (int)THIS->n, 1, &arg);
+ THIS->__retvalue = arg;
%}
-function _utrace_syscall_return:long () %{
- THIS->__retvalue = syscall_get_return_value(current, CONTEXT->regs); /* pure */
+function _utrace_syscall_return:long () %{ /* pure */
+ /*
+ * Here's the reason for the "unsigned long" cast. Since all
+ * values inside systemtap are 64-bit numbers, return values were
+ * getting sign extended. This caused return values to not match
+ * up with the same values passes as arguments.
+ */
+ THIS->__retvalue = (unsigned long)syscall_get_return_value(current,
+ CONTEXT->regs);
%}
diff --git a/testsuite/systemtap.base/static_uprobes.exp b/testsuite/systemtap.base/static_uprobes.exp
index 07ff83e9..1e53d5d3 100644
--- a/testsuite/systemtap.base/static_uprobes.exp
+++ b/testsuite/systemtap.base/static_uprobes.exp
@@ -93,7 +93,6 @@ if {[installtest_p]} {
if {[catch {exec $dtrace -h -s $sup_dpath} res]} {
verbose -log "unable to run $dtrace: $res"
}
-catch {exec rm -f $sup_dpath}
if {[file exists $sup_hpath]} then {
pass "$test dtrace"
} else {
diff --git a/testsuite/systemtap.base/utrace_syscall_args.c b/testsuite/systemtap.base/utrace_syscall_args.c
new file mode 100644
index 00000000..2d3da838
--- /dev/null
+++ b/testsuite/systemtap.base/utrace_syscall_args.c
@@ -0,0 +1,67 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h> /* For SYS_xxx definitions */
+
+int main()
+{
+ int fd, ret;
+ struct stat fs;
+ void *r;
+ int rc;
+
+ /* create a file with something in it */
+ fd = open("foobar", O_WRONLY|O_CREAT|O_TRUNC, 0600);
+ lseek(fd, 1024, SEEK_SET);
+ write(fd, "abcdef", 6);
+ close(fd);
+
+ fd = open("foobar", O_RDONLY);
+
+ /* stat for file size */
+ ret = fstat(fd, &fs);
+
+ /* mmap file file, then unmap it. */
+ r = mmap(NULL, fs.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (r != MAP_FAILED)
+ munmap(r, fs.st_size);
+ close(fd);
+
+ /* OK, try some system calls to see if we get the arguments
+ * correctly. */
+#if (__LONG_MAX__ > __INT_MAX__)
+ rc = syscall (__NR_dup, (unsigned long)-12345,
+ (unsigned long)0xffffffffffffffff,
+ (unsigned long)0xa5a5a5a5a5a5a5a5,
+ (unsigned long)0xf0f0f0f0f0f0f0f0,
+ (unsigned long)0x5a5a5a5a5a5a5a5a,
+ (unsigned long)0xe38e38e38e38e38e);
+#else
+ rc = syscall (__NR_dup, (unsigned long)-12345,
+ (unsigned long)0xffffffff,
+ (unsigned long)0xa5a5a5a5,
+ (unsigned long)0xf0f0f0f0,
+ (unsigned long)0x5a5a5a5a,
+ (unsigned long)0xe38e38e3);
+#endif
+#if (__LONG_MAX__ > __INT_MAX__)
+ rc = syscall ((unsigned long)-1,
+ (unsigned long)0x1c71c71c71c71c71,
+ (unsigned long)0x0f0f0f0f0f0f0f0f,
+ (unsigned long)0xdb6db6db6db6db6d,
+ (unsigned long)0x2492492492492492,
+ (unsigned long)0xad6b5ad6b5ad6b5a,
+ (unsigned long)0xdef7ddef7ddef7dd);
+#else
+ rc = syscall ((unsigned long)-1,
+ (unsigned long)0x1c71c71c,
+ (unsigned long)0x0f0f0f0f,
+ (unsigned long)0xdb6db6db,
+ (unsigned long)0x24924924,
+ (unsigned long)0xad6b5ad6,
+ (unsigned long)0xdef7ddef);
+#endif
+ return 0;
+}
diff --git a/testsuite/systemtap.base/utrace_syscall_args.exp b/testsuite/systemtap.base/utrace_syscall_args.exp
new file mode 100644
index 00000000..98bc457e
--- /dev/null
+++ b/testsuite/systemtap.base/utrace_syscall_args.exp
@@ -0,0 +1,82 @@
+# Utrace system call argument tests.
+
+set flags ""
+set srcpath "$srcdir/$subdir/utrace_syscall_args.c"
+set exepath "[pwd]/utrace_syscall_args"
+set stppath "$srcdir/$subdir/utrace_syscall_args.stp"
+
+set output_string "mmap\\(\[0-9\]+\\)\\(0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+\\) = 0x\[0-9a-f]+\r\nmunmap\\(\[0-9\]+\\)\\(0x\[0-9a-f]+, 0x\[0-9a-f]+\\) = 0x\[0-9a-f]+\r\nclose\\(\[0-9\]+\\)\\(0x\[0-9a-f]+\\) = 0x\[0-9a-f]+\r\ndup\\(\[0-9\]+\\)\\(0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+\\) = 0x\[0-9a-f]+\r\nbad_syscall\\(-?\[0-9\]+\\)\\(0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+\\) = 0x\[0-9a-f]+\r\nsystemtap test success\r\n"
+
+# For first pass, force 64-bit compilation for 64-bit systems. Add
+# any other 64-bit architecture you want tested below.
+#
+# To find tcl's platform name for your machine, run the following:
+# echo "puts $::tcl_platform(machine)" | tclsh
+
+switch -regexp $::tcl_platform(machine) {
+ ^ia64$ {
+ set do_64_bit_pass 1
+ set flags ""
+ }
+ ^(x86_64|ppc64|s390x)$ {
+ set do_64_bit_pass 1
+ set flags "additional_flags=-m64"
+ }
+ default {
+ set do_64_bit_pass 0
+ }
+}
+
+if {$do_64_bit_pass} {
+ set testname "64_BIT_UTRACE_SYSCALL_ARGS"
+ if {![installtest_p]} { untested $testname; continue }
+ if {![utrace_p]} { untested $testname; continue }
+ send_log "Testing ${testname}\n"
+
+ # Compile our test program.
+ set res [target_compile $srcpath $exepath executable $flags]
+ if { $res != "" } {
+ verbose "target_compile for $exepath failed: $res" 2
+ fail "$testname: unable to compile $srcpath"
+ return
+ }
+
+ # Run the test.
+ stap_run $testname no_load $output_string -g $stppath -c $exepath
+
+ catch {exec rm -f $exepath foobar}
+}
+
+# The second pass is for systems that support 32-bit executables
+# (either exclusively or in addition to 64-bit executables).
+set do_32_bit_pass 1
+switch -regexp $::tcl_platform(machine) {
+ ^(x86_64|ppc64)$ {
+ set flags "additional_flags=-m32"
+ }
+ ^s390x$ {
+ set flags "additional_flags=-m31"
+ }
+ ^ia64$ {
+ set do_32_bit_pass 0
+ }
+}
+
+if {$do_32_bit_pass} {
+ set testname "32_BIT_UTRACE_SYSCALL_ARGS"
+ if {![installtest_p]} { untested $testname; continue }
+ if {![utrace_p]} { untested $testname; continue }
+ send_log "Testing ${testname}\n"
+
+ # Compile our test program
+ set res [target_compile $srcpath $exepath executable $flags]
+ if { $res != "" } {
+ verbose "target_compile for $exepath failed: $res" 2
+ fail "$testname: unable to compile $srcpath"
+ return
+ }
+
+ stap_run $testname no_load $output_string -g $stppath -c $exepath
+
+ catch {exec rm -f $exepath foobar}
+}
diff --git a/testsuite/systemtap.base/utrace_syscall_args.stp b/testsuite/systemtap.base/utrace_syscall_args.stp
new file mode 100644
index 00000000..166e1ace
--- /dev/null
+++ b/testsuite/systemtap.base/utrace_syscall_args.stp
@@ -0,0 +1,366 @@
+%{
+#include "syscall.h"
+%}
+
+function mmap_syscall_no:long () %{
+ THIS->__retvalue = MMAP_SYSCALL_NO(current); /* pure */
+%}
+function mmap2_syscall_no:long () %{
+ THIS->__retvalue = MMAP2_SYSCALL_NO(current); /* pure */
+%}
+function munmap_syscall_no:long () %{
+ THIS->__retvalue = MUNMAP_SYSCALL_NO(current); /* pure */
+%}
+
+global syscalls_seen = 0
+global failures = 0
+
+global mmap_found = 0
+global mmap_args[10]
+
+global munmap_found = 0
+global munmap_args[10]
+
+global close_found = 0
+global close_args[10]
+
+global dup_found = 0
+global dup_args[10]
+
+global bad_syscall_found = 0
+global bad_syscall_args[10]
+
+probe begin
+{
+ printf("systemtap starting probe\n")
+}
+
+probe syscall.open {
+ if (filename == "foobar") {
+ syscalls_seen += 1
+ }
+}
+
+probe process("utrace_syscall_args").syscall {
+ if (syscalls_seen >= 2) {
+ syscalls_seen += 1
+
+ # We skip the fstat() syscall, which is the 1st syscall after
+ # the open() by not looking at 'syscalls_seen == 3'.
+
+ if (syscalls_seen == 4 && ($syscall == mmap_syscall_no()
+ || $syscall == mmap2_syscall_no())) {
+ mmap_found = 1
+ mmap_args[0] = $syscall
+ mmap_args[1] = $arg1
+ mmap_args[2] = $arg2
+ mmap_args[3] = $arg3
+ mmap_args[4] = $arg4
+ mmap_args[5] = $arg5
+ mmap_args[6] = $arg6
+
+%(arch == "s390x" %?
+ # s390 requires this for mmap. Verified by running:
+ # # strace strace utrace_syscall_args
+ addr = mmap_args[1]
+ mmap_args[1] = user_long(addr)
+ addr += 8
+ mmap_args[2] = user_long(addr)
+ addr += 8
+ mmap_args[3] = user_long(addr)
+ addr += 8
+ mmap_args[4] = user_long(addr)
+ addr += 8
+ mmap_args[5] = user_long(addr)
+ addr += 8
+ mmap_args[6] = user_long(addr)
+%)
+ }
+ else if (syscalls_seen == 5 && $syscall == munmap_syscall_no()) {
+ munmap_found = 1
+ munmap_args[0] = $syscall
+ munmap_args[1] = $arg1
+ munmap_args[2] = $arg2
+ }
+ else if (syscalls_seen == 6) {
+ close_found = 1
+ close_args[0] = $syscall
+ close_args[1] = $arg1
+ }
+ else if (syscalls_seen == 7) {
+ dup_found = 1
+ dup_args[0] = $syscall
+ dup_args[1] = $arg1
+ dup_args[2] = $arg2
+ dup_args[3] = $arg3
+ dup_args[4] = $arg4
+ dup_args[5] = $arg5
+ dup_args[6] = $arg6
+ }
+ else if (syscalls_seen == 8) {
+ bad_syscall_found = 1
+ bad_syscall_args[0] = $syscall
+ bad_syscall_args[1] = $arg1
+ bad_syscall_args[2] = $arg2
+ bad_syscall_args[3] = $arg3
+ bad_syscall_args[4] = $arg4
+ bad_syscall_args[5] = $arg5
+ bad_syscall_args[6] = $arg6
+ }
+ }
+}
+probe process("utrace_syscall_args").syscall.return {
+ if (syscalls_seen >= 4) {
+ if (syscalls_seen == 4) {
+ mmap_args[7] = $return
+ }
+ else if (syscalls_seen == 5) {
+ munmap_args[3] = $return
+ }
+ else if (syscalls_seen == 6) {
+ close_args[2] = $return
+ }
+ else if (syscalls_seen == 7) {
+ dup_args[7] = $return
+ }
+ else if (syscalls_seen == 8) {
+ bad_syscall_args[7] = $return
+ syscalls_seen = 0
+ }
+ }
+}
+
+probe end
+{
+ printf("systemtap ending probe\n")
+
+ # print mmap info
+ if (mmap_found == 0) {
+ printf("error: no mmap system call found\n")
+ failures += 1
+ }
+ else {
+ printf("mmap(%d)(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) = 0x%x\n",
+ mmap_args[0], mmap_args[1], mmap_args[2], mmap_args[3],
+ mmap_args[4], mmap_args[5], mmap_args[6], mmap_args[7])
+
+ # Validate arguments. We can only check certain arguments.
+ # It is possible that mmap's 'prot' and 'flags' arguments
+ # could vary per platform, so we'll ignore them.
+ if (mmap_args[1] != 0) {
+ failures += 1
+ printf("mmap bad arg 1: 0x%x vs 0x0\n", mmap_args[1])
+ }
+ if (mmap_args[2] != 0x406) {
+ failures += 1
+ printf("mmap bad arg 2: 0x%x vs 0x406\n", mmap_args[2])
+ }
+ if (mmap_args[6] != 0) {
+ failures += 1
+ printf("mmap bad arg 6: 0x%x vs 0x0\n", mmap_args[6])
+ }
+ }
+
+ # print munmap info
+ if (munmap_found == 0) {
+ printf("error: no munmap system call found\n")
+ failures += 1
+ }
+ else if (munmap_found == 0 || mmap_found == 0) {
+ printf("error: no munmap/mmap system call found\n")
+ failures += 1
+ }
+ else {
+ printf("munmap(%d)(0x%x, 0x%x) = 0x%x\n",
+ munmap_args[0], munmap_args[1], munmap_args[2], munmap_args[3])
+
+ # Validate arguments. munmap()'s first argument should be the
+ # same as the mmap() return value.
+ if (munmap_args[1] != mmap_args[7]) {
+ failures += 1
+ printf("munmap bad arg 1: 0x%x vs 0x%x\n", munmap_args[1],
+ mmap_args[7])
+ }
+ if (munmap_args[2] != mmap_args[2]) {
+ failures += 1
+ printf("munmap bad arg 2: 0x%x vs 0x%x\n", munmap_args[2],
+ mmap_args[2])
+ }
+ # Validate return value
+ if (munmap_args[7] != 0) {
+ failures += 1
+ printf("munmap bad return value: 0x%x vs 0x0\n", munmap_args[7])
+ }
+ }
+
+ # print close info
+ if (close_found == 0) {
+ printf("error: no close system call found\n")
+ failures += 1
+ }
+ else if (close_found == 1) {
+ printf("close(%d)(0x%x) = 0x%x\n",
+ close_args[0], close_args[1], close_args[2])
+
+ if (mmap_args[5] != close_args[1]) {
+ failures += 1
+ printf("close bad arg 1: 0x%x vs 0x%x\n",
+ close_args[0], mmap_args[5])
+ }
+ }
+
+ # print dup info
+ if (dup_found == 0) {
+ printf("error: no dup system call found\n")
+ failures += 1
+ }
+ else {
+ printf("dup(%d)(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) = 0x%x\n",
+ dup_args[0], dup_args[1], dup_args[2], dup_args[3],
+ dup_args[4], dup_args[5], dup_args[6], dup_args[7])
+
+ # Validate arguments - handle 32-bit vs. 64-bit.
+ if ((dup_args[1] & 0xffffffff00000000) != 0) {
+ if (dup_args[1] != 0xffffffffffffcfc7) {
+ failures += 1
+ printf("dup bad arg 1: 0x%x vs 0xffffffffffffcfc7\n",
+ dup_args[1])
+ }
+ if (dup_args[2] != 0xffffffffffffffff) {
+ failures += 1
+ printf("dup bad arg 2: 0x%x vs 0xffffffffffffffff\n",
+ dup_args[2])
+ }
+ if (dup_args[3] != 0xa5a5a5a5a5a5a5a5) {
+ failures += 1
+ printf("dup bad arg 3: 0x%x vs 0xa5a5a5a5a5a5a5a5\n",
+ dup_args[3])
+ }
+ if (dup_args[4] != 0xf0f0f0f0f0f0f0f0) {
+ failures += 1
+ printf("dup bad arg 4: 0x%x vs 0xf0f0f0f0f0f0f0f0\n",
+ dup_args[4])
+ }
+ if (dup_args[5] != 0x5a5a5a5a5a5a5a5a) {
+ failures += 1
+ printf("dup bad arg 5: 0x%x vs 0x5a5a5a5a5a5a5a5a\n",
+ dup_args[5])
+ }
+ if (dup_args[6] != 0xe38e38e38e38e38e) {
+ failures += 1
+ printf("dup bad arg 6: 0x%x vs 0xe38e38e38e38d38e\n",
+ dup_args[6])
+ }
+ }
+ else {
+ if (dup_args[1] != 0xffffcfc7) {
+ failures += 1
+ printf("dup bad arg 1: 0x%x vs 0xffffcfc7\n", dup_args[1])
+ }
+ if (dup_args[2] != 0xffffffff) {
+ failures += 1
+ printf("dup bad arg 2: 0x%x vs 0xffffffff\n", dup_args[2])
+ }
+ if (dup_args[3] != 0xa5a5a5a5) {
+ failures += 1
+ printf("dup bad arg 3: 0x%x vs 0xa5a5a5a5\n", dup_args[3])
+ }
+ if (dup_args[4] != 0xf0f0f0f0) {
+ failures += 4
+ printf("dup bad arg 4: 0x%x vs 0xf0f0f0f0\n", dup_args[4])
+ }
+ if (dup_args[5] != 0x5a5a5a5a) {
+ failures += 1
+ printf("dup bad arg 5: 0x%x vs 0x5a5a5a5a\n", dup_args[5])
+ }
+ if (dup_args[6] != 0xe38e38e3) {
+ failures += 1
+ printf("dup bad arg 6: 0x%x vs 0xe38e38e3\n", dup_args[6])
+ }
+ }
+ }
+
+ # print bad_syscall info
+ if (bad_syscall_found == 0) {
+ printf("error: no bad_syscall system call found\n")
+ failures += 1
+ }
+ else {
+ printf("bad_syscall(%d)(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) = 0x%x\n",
+ bad_syscall_args[0], bad_syscall_args[1], bad_syscall_args[2], bad_syscall_args[3],
+ bad_syscall_args[4], bad_syscall_args[5], bad_syscall_args[6], bad_syscall_args[7])
+
+ # Validate arguments - handle 32-bit vs. 64-bit.
+ if (bad_syscall_args[1] > 0xffffffff) {
+ if (bad_syscall_args[1] != 0x1c71c71c71c71c71) {
+ failures += 1
+ printf("bad_syscall bad arg 1: 0x%x vs 0x1c71c71c71c71c71\n",
+ bad_syscall_args[1])
+ }
+ if (bad_syscall_args[2] != 0x0f0f0f0f0f0f0f0f) {
+ failures += 1
+ printf("bad_syscall bad arg 2: 0x%x vs 0x0f0f0f0f0f0f0f0f\n",
+ bad_syscall_args[2])
+ }
+ if (bad_syscall_args[3] != 0xdb6db6db6db6db6d) {
+ failures += 1
+ printf("bad_syscall bad arg 3: 0x%x vs 0xdb6db6db6db6db6d\n",
+ bad_syscall_args[3])
+ }
+ if (bad_syscall_args[4] != 0x2492492492492492) {
+ failures += 1
+ printf("bad_syscall bad arg 4: 0x%x vs 0x2492492492492492\n",
+ bad_syscall_args[4])
+ }
+ if (bad_syscall_args[5] != 0xad6b5ad6b5ad6b5a) {
+ failures += 1
+ printf("bad_syscall bad arg 5: 0x%x vs 0xad6b5ad6b5ad6b5a\n",
+ bad_syscall_args[5])
+ }
+ if (bad_syscall_args[6] != 0xdef7ddef7ddef7dd) {
+ failures += 1
+ printf("bad_syscall bad arg 6: 0x%x vs 0xdef7ddef7ddef7dd\n",
+ bad_syscall_args[6])
+ }
+ }
+ else {
+ if (bad_syscall_args[1] != 0x1c71c71c) {
+ failures += 1
+ printf("bad_syscall bad arg 1: 0x%x vs 0x1c71c71c\n",
+ bad_syscall_args[1])
+ }
+ if (bad_syscall_args[2] != 0x0f0f0f0f) {
+ failures += 1
+ printf("bad_syscall bad arg 2: 0x%x vs 0x0f0f0f0f\n",
+ bad_syscall_args[2])
+ }
+ if (bad_syscall_args[3] != 0xdb6db6db) {
+ failures += 1
+ printf("bad_syscall bad arg 3: 0x%x vs 0xdb6db6db\n",
+ bad_syscall_args[3])
+ }
+ if (bad_syscall_args[4] != 0x24924924) {
+ failures += 4
+ printf("bad_syscall bad arg 4: 0x%x vs 0x24924924\n",
+ bad_syscall_args[4])
+ }
+ if (bad_syscall_args[5] != 0xad6b5ad6) {
+ failures += 1
+ printf("bad_syscall bad arg 5: 0x%x vs 0xad6b5ad6\n",
+ bad_syscall_args[5])
+ }
+ if (bad_syscall_args[6] != 0xdef7ddef) {
+ failures += 1
+ printf("bad_syscall bad arg 6: 0x%x vs 0xdef7ddef\n",
+ bad_syscall_args[6])
+ }
+ }
+ }
+
+ if (failures == 0) {
+ printf("systemtap test success\n")
+ }
+ else {
+ printf("systemtap test failure\n")
+ }
+}
diff --git a/testsuite/systemtap.examples/general/grapher.stp b/testsuite/systemtap.examples/general/grapher.stp
new file mode 100644
index 00000000..04463979
--- /dev/null
+++ b/testsuite/systemtap.examples/general/grapher.stp
@@ -0,0 +1,32 @@
+#! /usr/bin/stap
+
+probe begin
+{
+printf ("%s\n", "%Title:CPU utilization");
+printf ("%s\n", "%XAxisTitle:Time");
+printf ("%s\n", "%YAxisTitle:Percent");
+printf ("%s\n", "%DataSet:cpu 100 00ff00 bar");
+printf ("%s\n", "%DataSet:kbd 100 ff0000 dot");
+}
+
+# CPU utilization
+probe begin { qnames["cpu"] ++; qsq_start ("cpu") }
+probe scheduler.cpu_on { if (!idle) {qs_wait ("cpu") qs_run ("cpu") }}
+probe scheduler.cpu_off { if (!idle) qs_done ("cpu") }
+
+global qnames
+
+function qsq_util_reset(q) {
+ u=qsq_utilization (q, 100)
+ qsq_start (q)
+ return u
+}
+
+probe timer.ms(100) { # collect utilization percentages frequently
+ foreach (q in qnames)
+ printf("cpu %d %d\n", gettimeofday_ms(), qsq_util_reset(q))
+}
+
+probe kernel.function("kbd_event") {
+ printf("kbd %d %d\n", gettimeofday_ms(), 75)
+}
diff --git a/testsuite/systemtap.examples/index.html b/testsuite/systemtap.examples/index.html
index a03b8dcc..a2dc7d5c 100644
--- a/testsuite/systemtap.examples/index.html
+++ b/testsuite/systemtap.examples/index.html
@@ -88,6 +88,9 @@ keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <br>
<li><a href="memory/pfaults.stp">memory/pfaults.stp</a> - Generate Log of Major and Minor Page Faults<br>
keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <br>
<p>The pfaults.stp script generates a simple log for each major and minor page fault that occurs on the system. Each line contains a timestamp (in microseconds) when the page fault servicing was completed, the pid of the process, the address of the page fault, the type of access (read or write), the type of fault (major or minor), and the elapsed time for page fault. This log can be examined to determine where the page faults are occuring.</p></li>
+<li><a href="network/dropwatch.stp">network/dropwatch.stp</a> - Watch Where Socket Buffers are Freed in the Kernel<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <a href="keyword-index.html#BUFFER">BUFFER</a> <a href="keyword-index.html#FREE">FREE</a> <br>
+<p>Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.</p></li>
<li><a href="network/nettop.stp">network/nettop.stp</a> - Periodic Listing of Processes Using Network Interfaces<br>
keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRAFFIC">TRAFFIC</a> <a href="keyword-index.html#PER-PROCESS">PER-PROCESS</a> <br>
<p>Every five seconds the nettop.stp script prints out a list of processed (PID and command) with the number of packets sent/received and the amount of data sent/received by the process during that interval.</p></li>
diff --git a/testsuite/systemtap.examples/index.txt b/testsuite/systemtap.examples/index.txt
index d24232e7..2f85628a 100644
--- a/testsuite/systemtap.examples/index.txt
+++ b/testsuite/systemtap.examples/index.txt
@@ -152,6 +152,13 @@ keywords: memory
determine where the page faults are occuring.
+network/dropwatch.stp - Watch Where Socket Buffers are Freed in the Kernel
+keywords: network tracepoint buffer free
+
+ Every five seconds the dropwatch.stp script lists the number of
+ socket buffers freed at locations in the kernel.
+
+
network/nettop.stp - Periodic Listing of Processes Using Network Interfaces
keywords: network traffic per-process
diff --git a/testsuite/systemtap.examples/keyword-index.html b/testsuite/systemtap.examples/keyword-index.html
index e65ed19d..473c0091 100644
--- a/testsuite/systemtap.examples/keyword-index.html
+++ b/testsuite/systemtap.examples/keyword-index.html
@@ -39,7 +39,7 @@
</ul>
<h2>Examples by Keyword</h2>
-<p><tt><a href="#BACKTRACE">BACKTRACE</a> <a href="#CALLGRAPH">CALLGRAPH</a> <a href="#CPU">CPU</a> <a href="#DISK">DISK</a> <a href="#FORMAT">FORMAT</a> <a href="#FUNCTIONS">FUNCTIONS</a> <a href="#FUTEX">FUTEX</a> <a href="#GRAPH">GRAPH</a> <a href="#INTERRUPT">INTERRUPT</a> <a href="#IO">IO</a> <a href="#LOCKING">LOCKING</a> <a href="#MEMORY">MEMORY</a> <a href="#NETWORK">NETWORK</a> <a href="#PER-PROCESS">PER-PROCESS</a> <a href="#PROCESS">PROCESS</a> <a href="#PROFILING">PROFILING</a> <a href="#READ">READ</a> <a href="#SCHEDULER">SCHEDULER</a> <a href="#SIGNALS">SIGNALS</a> <a href="#SIMPLE">SIMPLE</a> <a href="#SLEEP">SLEEP</a> <a href="#SOCKET">SOCKET</a> <a href="#SYSCALL">SYSCALL</a> <a href="#TCP">TCP</a> <a href="#TIME">TIME</a> <a href="#TRACE">TRACE</a> <a href="#TRAFFIC">TRAFFIC</a> <a href="#USE">USE</a> <a href="#WAIT4">WAIT4</a> <a href="#WRITE">WRITE</a> </tt></p>
+<p><tt><a href="#BACKTRACE">BACKTRACE</a> <a href="#BUFFER">BUFFER</a> <a href="#CALLGRAPH">CALLGRAPH</a> <a href="#CPU">CPU</a> <a href="#DISK">DISK</a> <a href="#FORMAT">FORMAT</a> <a href="#FREE">FREE</a> <a href="#FUNCTIONS">FUNCTIONS</a> <a href="#FUTEX">FUTEX</a> <a href="#GRAPH">GRAPH</a> <a href="#INTERRUPT">INTERRUPT</a> <a href="#IO">IO</a> <a href="#LOCKING">LOCKING</a> <a href="#MEMORY">MEMORY</a> <a href="#NETWORK">NETWORK</a> <a href="#PER-PROCESS">PER-PROCESS</a> <a href="#PROCESS">PROCESS</a> <a href="#PROFILING">PROFILING</a> <a href="#READ">READ</a> <a href="#SCHEDULER">SCHEDULER</a> <a href="#SIGNALS">SIGNALS</a> <a href="#SIMPLE">SIMPLE</a> <a href="#SLEEP">SLEEP</a> <a href="#SOCKET">SOCKET</a> <a href="#SYSCALL">SYSCALL</a> <a href="#TCP">TCP</a> <a href="#TIME">TIME</a> <a href="#TRACE">TRACE</a> <a href="#TRACEPOINT">TRACEPOINT</a> <a href="#TRAFFIC">TRAFFIC</a> <a href="#USE">USE</a> <a href="#WAIT4">WAIT4</a> <a href="#WRITE">WRITE</a> </tt></p>
<h3><a name="BACKTRACE">BACKTRACE</a></h3>
<ul>
<li><a href="interrupt/scf.stp">interrupt/scf.stp</a> - Tally Backtraces for Inter-Processor Interrupt (IPI)<br>
@@ -52,6 +52,12 @@ keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#BAC
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#SCHEDULER">SCHEDULER</a> <a href="keyword-index.html#BACKTRACE">BACKTRACE</a> <br>
<p>The script monitors the time that threads spend waiting for IO operations (in "D" state) in the wait_for_completion function. If a thread spends over 10ms, its name and backtrace is printed, and later so is the total delay.</p></li>
</ul>
+<h3><a name="BUFFER">BUFFER</a></h3>
+<ul>
+<li><a href="network/dropwatch.stp">network/dropwatch.stp</a> - Watch Where Socket Buffers are Freed in the Kernel<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <a href="keyword-index.html#BUFFER">BUFFER</a> <a href="keyword-index.html#FREE">FREE</a> <br>
+<p>Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.</p></li>
+</ul>
<h3><a name="CALLGRAPH">CALLGRAPH</a></h3>
<ul>
<li><a href="general/para-callgraph.stp">general/para-callgraph.stp</a> - Callgraph tracing with arguments<br>
@@ -82,6 +88,12 @@ keywords: <a href="keyword-index.html#FORMAT">FORMAT</a> <br>
keywords: <a href="keyword-index.html#FORMAT">FORMAT</a> <br>
<p>The script prints a table showing the available attributes (bold, underline, and inverse) with color combinations for the ans_set_color3() function in the ansi.stp tapset.</p></li>
</ul>
+<h3><a name="FREE">FREE</a></h3>
+<ul>
+<li><a href="network/dropwatch.stp">network/dropwatch.stp</a> - Watch Where Socket Buffers are Freed in the Kernel<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <a href="keyword-index.html#BUFFER">BUFFER</a> <a href="keyword-index.html#FREE">FREE</a> <br>
+<p>Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.</p></li>
+</ul>
<h3><a name="FUNCTIONS">FUNCTIONS</a></h3>
<ul>
<li><a href="profiling/functioncallcount.stp">profiling/functioncallcount.stp</a> - Count Times Functions Called<br>
@@ -150,6 +162,9 @@ keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <br>
</ul>
<h3><a name="NETWORK">NETWORK</a></h3>
<ul>
+<li><a href="network/dropwatch.stp">network/dropwatch.stp</a> - Watch Where Socket Buffers are Freed in the Kernel<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <a href="keyword-index.html#BUFFER">BUFFER</a> <a href="keyword-index.html#FREE">FREE</a> <br>
+<p>Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.</p></li>
<li><a href="network/nettop.stp">network/nettop.stp</a> - Periodic Listing of Processes Using Network Interfaces<br>
keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRAFFIC">TRAFFIC</a> <a href="keyword-index.html#PER-PROCESS">PER-PROCESS</a> <br>
<p>Every five seconds the nettop.stp script prints out a list of processed (PID and command) with the number of packets sent/received and the amount of data sent/received by the process during that interval.</p></li>
@@ -286,6 +301,12 @@ keywords: <a href="keyword-index.html#SYSCALL">SYSCALL</a> <a href="keyword-inde
keywords: <a href="keyword-index.html#TRACE">TRACE</a> <a href="keyword-index.html#CALLGRAPH">CALLGRAPH</a> <br>
<p>Print a timed per-thread callgraph, complete with function parameters and return values. The first parameter names the function probe points to trace. The optional second parameter names the probe points for trigger functions, which acts to enable tracing for only those functions that occur while the current thread is nested within the trigger.</p></li>
</ul>
+<h3><a name="TRACEPOINT">TRACEPOINT</a></h3>
+<ul>
+<li><a href="network/dropwatch.stp">network/dropwatch.stp</a> - Watch Where Socket Buffers are Freed in the Kernel<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <a href="keyword-index.html#BUFFER">BUFFER</a> <a href="keyword-index.html#FREE">FREE</a> <br>
+<p>Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.</p></li>
+</ul>
<h3><a name="TRAFFIC">TRAFFIC</a></h3>
<ul>
<li><a href="network/nettop.stp">network/nettop.stp</a> - Periodic Listing of Processes Using Network Interfaces<br>
diff --git a/testsuite/systemtap.examples/keyword-index.txt b/testsuite/systemtap.examples/keyword-index.txt
index 40b5276f..1d5add5f 100644
--- a/testsuite/systemtap.examples/keyword-index.txt
+++ b/testsuite/systemtap.examples/keyword-index.txt
@@ -30,6 +30,15 @@ keywords: io scheduler backtrace
so is the total delay.
+= BUFFER =
+
+network/dropwatch.stp - Watch Where Socket Buffers are Freed in the Kernel
+keywords: network tracepoint buffer free
+
+ Every five seconds the dropwatch.stp script lists the number of
+ socket buffers freed at locations in the kernel.
+
+
= CALLGRAPH =
general/para-callgraph.stp - Callgraph tracing with arguments
@@ -88,6 +97,15 @@ keywords: format
ans_set_color3() function in the ansi.stp tapset.
+= FREE =
+
+network/dropwatch.stp - Watch Where Socket Buffers are Freed in the Kernel
+keywords: network tracepoint buffer free
+
+ Every five seconds the dropwatch.stp script lists the number of
+ socket buffers freed at locations in the kernel.
+
+
= FUNCTIONS =
profiling/functioncallcount.stp - Count Times Functions Called
@@ -251,6 +269,13 @@ keywords: memory
= NETWORK =
+network/dropwatch.stp - Watch Where Socket Buffers are Freed in the Kernel
+keywords: network tracepoint buffer free
+
+ Every five seconds the dropwatch.stp script lists the number of
+ socket buffers freed at locations in the kernel.
+
+
network/nettop.stp - Periodic Listing of Processes Using Network Interfaces
keywords: network traffic per-process
@@ -594,6 +619,15 @@ keywords: trace callgraph
the trigger.
+= TRACEPOINT =
+
+network/dropwatch.stp - Watch Where Socket Buffers are Freed in the Kernel
+keywords: network tracepoint buffer free
+
+ Every five seconds the dropwatch.stp script lists the number of
+ socket buffers freed at locations in the kernel.
+
+
= TRAFFIC =
network/nettop.stp - Periodic Listing of Processes Using Network Interfaces
diff --git a/testsuite/systemtap.examples/network/dropwatch.meta b/testsuite/systemtap.examples/network/dropwatch.meta
new file mode 100644
index 00000000..176ba236
--- /dev/null
+++ b/testsuite/systemtap.examples/network/dropwatch.meta
@@ -0,0 +1,13 @@
+title: Watch Where Socket Buffers are Freed in the Kernel
+name: dropwatch.stp
+version: 1.0
+author: Neil Horman
+keywords: network tracepoint buffer free
+subsystem: network
+status: production
+exit: user-controlled
+output: timed
+scope: system-wide
+description: Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.
+test_check: stap -p4 dropwatch.stp
+test_installcheck: stap dropwatch.stp -c "sleep 1"
diff --git a/testsuite/systemtap.examples/network/dropwatch.stp b/testsuite/systemtap.examples/network/dropwatch.stp
new file mode 100755
index 00000000..79d50a4e
--- /dev/null
+++ b/testsuite/systemtap.examples/network/dropwatch.stp
@@ -0,0 +1,30 @@
+#! /usr/bin/env stap
+
+############################################################
+# Dropwatch.stp
+# Author: Neil Horman <nhorman@redhat.com>
+# An example script to mimic the behavior of the dropwatch utility
+# http://fedorahosted.org/dropwatch
+############################################################
+
+# Array to hold the list of drop points we find
+global locations
+
+# Note when we turn the monitor on and off
+probe begin { printf("Monitoring for dropped packets\n") }
+probe end { printf("Stopping dropped packet monitor\n") }
+
+# increment a drop counter for every location we drop at
+probe kernel.trace("kfree_skb") { locations[$location] <<< 1 }
+
+# Every 5 seconds report our drop locations
+probe timer.sec(5)
+{
+ printf("\n")
+ foreach (l in locations-) {
+ printf("%d packets dropped at location %p\n",
+ @count(locations[l]), l)
+ }
+ delete locations
+}
+
diff --git a/translate.cxx b/translate.cxx
index c3c5533c..a6357766 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -4848,6 +4848,7 @@ dump_unwindsyms (Dwfl_Module *m,
// Emit symbol table & unwind data, plus any calls needed to register
// them with the runtime.
+void emit_symbol_data_done (unwindsym_dump_context*, systemtap_session&);
void
emit_symbol_data (systemtap_session& s)
@@ -4860,6 +4861,14 @@ emit_symbol_data (systemtap_session& s)
unwindsym_dump_context ctx = { s, kallsyms_out, 0, s.unwindsym_modules };
+ // Micro optimization, mainly to speed up tiny regression tests
+ // using just begin probe.
+ if (s.unwindsym_modules.size () == 0)
+ {
+ emit_symbol_data_done(&ctx, s);
+ return;
+ }
+
// XXX: copied from tapsets.cxx dwflpp::, sadly
static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build";
static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH");
@@ -4952,20 +4961,25 @@ emit_symbol_data (systemtap_session& s)
dwfl_end(dwfl);
}
+ emit_symbol_data_done (&ctx, s);
+}
+void
+emit_symbol_data_done (unwindsym_dump_context *ctx, systemtap_session& s)
+{
// Print out a definition of the runtime's _stp_modules[] globals.
- kallsyms_out << "\n";
- kallsyms_out << "static struct _stp_module *_stp_modules [] = {\n";
- for (unsigned i=0; i<ctx.stp_module_index; i++)
+ ctx->output << "\n";
+ ctx->output << "static struct _stp_module *_stp_modules [] = {\n";
+ for (unsigned i=0; i<ctx->stp_module_index; i++)
{
- kallsyms_out << "& _stp_module_" << i << ",\n";
+ ctx->output << "& _stp_module_" << i << ",\n";
}
- kallsyms_out << "};\n";
- kallsyms_out << "static unsigned _stp_num_modules = " << ctx.stp_module_index << ";\n";
+ ctx->output << "};\n";
+ ctx->output << "static unsigned _stp_num_modules = " << ctx->stp_module_index << ";\n";
// Some nonexistent modules may have been identified with "-d". Note them.
- for (set<string>::iterator it = ctx.undone_unwindsym_modules.begin();
- it != ctx.undone_unwindsym_modules.end();
+ for (set<string>::iterator it = ctx->undone_unwindsym_modules.begin();
+ it != ctx->undone_unwindsym_modules.end();
it ++)
{
s.print_warning ("missing unwind/symbol data for module '" + (*it) + "'");