summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rw-r--r--Makefile.in21
-rwxr-xr-xconfigure77
-rw-r--r--configure.ac3
-rw-r--r--coveragedb.cxx322
-rw-r--r--coveragedb.h70
-rw-r--r--elaborate.cxx28
-rw-r--r--elaborate.h1
-rw-r--r--main.cxx20
-rw-r--r--session.h5
-rw-r--r--staptree.cxx25
-rw-r--r--staptree.h5
-rw-r--r--systemtap.spec.in2
13 files changed, 574 insertions, 9 deletions
diff --git a/Makefile.am b/Makefile.am
index 5c9a37d0..4b81c83d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -15,8 +15,8 @@ bin_PROGRAMS = stap staprun
stap_SOURCES = main.cxx \
parse.cxx staptree.cxx elaborate.cxx translate.cxx \
tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \
- cache.cxx util.cxx
-stap_LDADD = @stap_LIBS@
+ cache.cxx util.cxx coveragedb.cxx
+stap_LDADD = @stap_LIBS@ -lsqlite3
stap_CXXFLAGS = $(AM_CXXFLAGS)
stap_CPPFLAGS = $(AM_CPPFLAGS)
diff --git a/Makefile.in b/Makefile.in
index 2bfa676e..1b1ff3f8 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -96,7 +96,7 @@ am_stap_OBJECTS = stap-main.$(OBJEXT) stap-parse.$(OBJEXT) \
stap-translate.$(OBJEXT) stap-tapsets.$(OBJEXT) \
stap-buildrun.$(OBJEXT) stap-loc2c.$(OBJEXT) \
stap-hash.$(OBJEXT) stap-mdfour.$(OBJEXT) stap-cache.$(OBJEXT) \
- stap-util.$(OBJEXT)
+ stap-util.$(OBJEXT) stap-coveragedb.$(OBJEXT)
stap_OBJECTS = $(am_stap_OBJECTS)
stap_LINK = $(CXXLD) $(stap_CXXFLAGS) $(CXXFLAGS) $(stap_LDFLAGS) \
$(LDFLAGS) -o $@
@@ -268,9 +268,9 @@ dist_man_MANS = stap.1 stapprobes.5 stapfuncs.5 stapex.5 staprun.8 lket.5 lket-b
stap_SOURCES = main.cxx \
parse.cxx staptree.cxx elaborate.cxx translate.cxx \
tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \
- cache.cxx util.cxx
+ cache.cxx util.cxx coveragedb.cxx
-stap_LDADD = @stap_LIBS@
+stap_LDADD = @stap_LIBS@ -lsqlite3
stap_CXXFLAGS = $(AM_CXXFLAGS)
stap_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_1)
stap_LDFLAGS = $(AM_LDFLAGS) $(am__append_2)
@@ -478,6 +478,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loc2c_test-loc2c.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-buildrun.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-cache.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-coveragedb.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-elaborate.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-hash.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-loc2c.Po@am__quote@
@@ -817,6 +818,20 @@ stap-util.obj: util.cxx
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='util.cxx' object='stap-util.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-util.obj `if test -f 'util.cxx'; then $(CYGPATH_W) 'util.cxx'; else $(CYGPATH_W) '$(srcdir)/util.cxx'; fi`
+
+stap-coveragedb.o: coveragedb.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-coveragedb.o -MD -MP -MF $(DEPDIR)/stap-coveragedb.Tpo -c -o stap-coveragedb.o `test -f 'coveragedb.cxx' || echo '$(srcdir)/'`coveragedb.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-coveragedb.Tpo $(DEPDIR)/stap-coveragedb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='coveragedb.cxx' object='stap-coveragedb.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-coveragedb.o `test -f 'coveragedb.cxx' || echo '$(srcdir)/'`coveragedb.cxx
+
+stap-coveragedb.obj: coveragedb.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-coveragedb.obj -MD -MP -MF $(DEPDIR)/stap-coveragedb.Tpo -c -o stap-coveragedb.obj `if test -f 'coveragedb.cxx'; then $(CYGPATH_W) 'coveragedb.cxx'; else $(CYGPATH_W) '$(srcdir)/coveragedb.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-coveragedb.Tpo $(DEPDIR)/stap-coveragedb.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='coveragedb.cxx' object='stap-coveragedb.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-coveragedb.obj `if test -f 'coveragedb.cxx'; then $(CYGPATH_W) 'coveragedb.cxx'; else $(CYGPATH_W) '$(srcdir)/coveragedb.cxx'; fi`
install-man1: $(man1_MANS) $(man_MANS)
@$(NORMAL_INSTALL)
test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
diff --git a/configure b/configure
index 5e4d326d..5e034dc8 100755
--- a/configure
+++ b/configure
@@ -6657,6 +6657,83 @@ fi
{ echo "$as_me:$LINENO: stap will link $stap_LIBS" >&5
echo "$as_me: stap will link $stap_LIBS" >&6;}
+
+{ echo "$as_me:$LINENO: checking for sqlite3_open in -lsqlite3" >&5
+echo $ECHO_N "checking for sqlite3_open in -lsqlite3... $ECHO_C" >&6; }
+if test "${ac_cv_lib_sqlite3_sqlite3_open+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsqlite3 $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sqlite3_open ();
+int
+main ()
+{
+return sqlite3_open ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_sqlite3_sqlite3_open=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_sqlite3_sqlite3_open=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_sqlite3_sqlite3_open" >&5
+echo "${ECHO_T}$ac_cv_lib_sqlite3_sqlite3_open" >&6; }
+if test $ac_cv_lib_sqlite3_sqlite3_open = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSQLITE3 1
+_ACEOF
+
+ LIBS="-lsqlite3 $LIBS"
+
+else
+
+ { { echo "$as_me:$LINENO: error: missing sqlite development headers/libraries" >&5
+echo "$as_me: error: missing sqlite development headers/libraries" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+
date=`date +%Y-%m-%d`
cat >>confdefs.h <<_ACEOF
diff --git a/configure.ac b/configure.ac
index 5b0c75ee..ec619094 100644
--- a/configure.ac
+++ b/configure.ac
@@ -140,6 +140,9 @@ fi
AC_SUBST(stap_LIBS)
AC_MSG_NOTICE([stap will link $stap_LIBS])
+AC_CHECK_HEADER(sqlite3.h, AC_CHECK_LIB(sqlite3, sqlite3_open,
+ AC_MSG_ERROR([missing sqlite development headers/libraries])])
+
dnl Plop in the build (configure) date
date=`date +%Y-%m-%d`
AC_DEFINE_UNQUOTED(DATE, "$date", [Configuration/build date])
diff --git a/coveragedb.cxx b/coveragedb.cxx
new file mode 100644
index 00000000..69eb95b4
--- /dev/null
+++ b/coveragedb.cxx
@@ -0,0 +1,322 @@
+// coveragedb.cxx
+// Copyright (C) 2007 Red Hat Inc.
+//
+// This file is part of systemtap, and is free software. You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+#include "parse.h"
+#include "coveragedb.h"
+#include "config.h"
+#include "elaborate.h"
+#include "tapsets.h"
+#include "session.h"
+#include "util.h"
+
+#include <iostream>
+#include <sqlite3.h>
+
+using namespace std;
+
+void print_coverage_info(systemtap_session &s)
+{
+ vector<derived_probe*> used_probe_list;
+ vector<derived_probe*> unused_probe_list;
+ // print out used probes
+ clog << "---- used probes-----" << endl;
+ for (unsigned i=0; i<s.probes.size(); i++) {
+ // walk through the chain of probes
+ s.probes[i]->collect_derivation_chain(used_probe_list);
+ for (unsigned j=0; j<used_probe_list.size(); ++j) {
+ for (unsigned k=0; k< used_probe_list[j]->locations.size(); ++k)
+ clog << "probe: "
+ << used_probe_list[j]->locations[k]->tok->location << endl;
+ }
+
+ clog << "----" << endl;
+ // for each probe print used and unused variables
+ for (unsigned j=0; j<s.probes[i]->locals.size(); ++j) {
+ clog << "local: " << s.probes[i]->locals[j]->tok->location << endl;
+ }
+ for (unsigned j=0; j<s.probes[i]->unused_locals.size(); ++j) {
+ clog << "unused_local: "
+ << s.probes[i]->unused_locals[j]->tok->location
+ << endl;
+ }
+ }
+ // print out unused probes
+ clog << "---- unused probes----- " << endl;
+ for (unsigned i=0; i<s.unused_probes.size(); i++) {
+ // walk through the chain of probes
+ s.probes[i]->collect_derivation_chain(unused_probe_list);
+ for (unsigned j=0; j<unused_probe_list.size(); ++j) {
+ for (unsigned k=0; k< unused_probe_list[j]->locations.size(); ++k)
+ clog << "probe: "
+ << unused_probe_list[j]->locations[k]->tok->location << endl;
+ }
+
+ }
+ // print out used functions
+ clog << "---- used functions----- " << endl;
+ for (unsigned i=0; i<s.functions.size(); i++) {
+ clog << "function: " << s.functions[i]->tok->location
+ << " " << s.functions[i]->name
+ << endl;
+ }
+ // print out unused functions
+ clog << "---- unused functions----- " << endl;
+ for (unsigned i=0; i<s.unused_functions.size(); i++) {
+ clog << "unused_function: " << s.unused_functions[i]->tok->location
+ << " " << s.unused_functions[i]->name
+ << endl;
+ }
+ // print out used globals
+ clog << "---- used globals----- " << endl;
+ for (unsigned i=0; i<s.globals.size(); i++) {
+ clog << "globals: " << s.globals[i]->tok->location
+ << " " << s.globals[i]->name
+ << endl;
+ }
+ // print out unused globals
+ clog << "---- unused globals----- " << endl;
+ for (unsigned i=0; i<s.unused_globals.size(); i++) {
+ clog << "globals: " << s.unused_globals[i]->tok->location
+ << " " << s.unused_globals[i]->name
+ << endl;
+ }
+}
+
+
+void sql_stmt(sqlite3 *db, const char* stmt)
+{
+ char *errmsg;
+ int ret;
+
+ // cerr << "sqlite: " << stmt << endl;
+
+ ret = sqlite3_exec(db, stmt, 0, 0, &errmsg);
+
+ if(ret != SQLITE_OK) {
+ cerr << "Error in statement: " << stmt << " [" << errmsg << "]."
+ << endl;
+ }
+}
+
+void enter_element(sqlite3 *db, coverage_element &x)
+{
+ ostringstream command;
+ command << "insert or ignore into counts values ('"
+ << x.file << "', '"
+ << x.line << "', '"
+ << x.col << "', '"
+ << x.type << "','"
+ << x.name << "', '"
+ << x.parent <<"',"
+ << "'0', '0', '0')";
+ sql_stmt(db, command.str().c_str());
+}
+
+void increment_element(sqlite3 *db, coverage_element &x)
+{
+ // make sure value in table
+ enter_element(db, x);
+ // increment appropriate value
+ if (x.compiled) {
+ ostringstream command;
+ command << "update counts set compiled = compiled + "
+ << x.compiled << " where ("
+ << "file == '" << x.file << "' and "
+ << "line == '" << x.line << "' and "
+ << "col == '" << x.col << "')";
+ sql_stmt(db, command.str().c_str());
+ }
+ if (x.removed) {
+ ostringstream command;
+ command << "update counts set removed = removed + "
+ << x.removed << " where ("
+ << "file == '" << x.file << "' and "
+ << "line == '" << x.line << "' and "
+ << "col == '" << x.col << "')";
+ sql_stmt(db, command.str().c_str());
+ }
+}
+
+
+void
+sql_update_used_probes(sqlite3 *db, systemtap_session &s)
+{
+ vector<derived_probe*> used_probe_list;
+
+ // update database used probes
+ for (unsigned i=0; i<s.probes.size(); i++) {
+ // walk through the chain of probes
+ s.probes[i]->collect_derivation_chain(used_probe_list);
+ for (unsigned j=0; j<used_probe_list.size(); ++j) {
+ for (unsigned k=0; k< used_probe_list[j]->locations.size(); ++k){
+ struct source_loc place = used_probe_list[j]->locations[k]->tok->location;
+ coverage_element x(place);
+
+ x.type = string("p");
+ x.name = used_probe_list[j]->locations[k]->str();
+ x.compiled = 1;
+ increment_element(db, x);
+ }
+ }
+
+ // for each probe update used and unused variables
+ for (unsigned j=0; j<s.probes[i]->locals.size(); ++j) {
+ struct source_loc place = s.probes[i]->locals[j]->tok->location;
+ coverage_element x(place);
+
+ x.type = string("l");
+ x.name = s.probes[i]->locals[j]->tok->content;
+ x.compiled = 1;
+ increment_element(db, x);
+ }
+ for (unsigned j=0; j<s.probes[i]->unused_locals.size(); ++j) {
+ struct source_loc place = s.probes[i]->unused_locals[j]->tok->location;
+ coverage_element x(place);
+
+ x.type = string("l");
+ x.name = s.probes[i]->unused_locals[j]->tok->content;
+ x.removed = 1;
+ increment_element(db, x);
+ }
+ }
+}
+
+
+void
+sql_update_unused_probes(sqlite3 *db, systemtap_session &s)
+{
+ vector<derived_probe*> unused_probe_list;
+
+ // update database unused probes
+ for (unsigned i=0; i<s.unused_probes.size(); i++) {
+ // walk through the chain of probes
+ s.probes[i]->collect_derivation_chain(unused_probe_list);
+ for (unsigned j=0; j<unused_probe_list.size(); ++j) {
+ for (unsigned k=0; k< unused_probe_list[j]->locations.size(); ++k) {
+
+ struct source_loc place = unused_probe_list[j]->locations[k]->tok->location;
+ coverage_element x(place);
+
+ x.type = string("p");
+ x.name = unused_probe_list[j]->locations[k]->str();
+ x.removed = 1;
+ increment_element(db, x);
+ }
+ }
+ }
+}
+
+
+void
+sql_update_used_functions(sqlite3 *db, systemtap_session &s)
+{
+ // update db used functions
+ for (unsigned i=0; i<s.functions.size(); i++) {
+ struct source_loc place = s.functions[i]->tok->location;
+ coverage_element x(place);
+
+ x.type = string("f");
+ x.name = s.functions[i]->name;
+ x.compiled = 1;
+ increment_element(db, x);
+ }
+}
+
+
+void
+sql_update_unused_functions(sqlite3 *db, systemtap_session &s)
+{
+ // update db unused functions
+ for (unsigned i=0; i<s.unused_functions.size(); i++) {
+ struct source_loc place = s.unused_functions[i]->tok->location;
+ coverage_element x(place);
+
+ x.type = string("f");
+ x.name = s.unused_functions[i]->name;
+ x.removed = 1;
+ increment_element(db, x);
+ }
+}
+
+
+void
+sql_update_used_globals(sqlite3 *db, systemtap_session &s)
+{
+ // update db used globals
+ for (unsigned i=0; i<s.globals.size(); i++) {
+ sql_stmt(db, "--");
+ struct source_loc place = s.globals[i]->tok->location;
+ coverage_element x(place);
+
+ x.type = string("g");
+ x.name = s.globals[i]->name;
+ x.compiled = 1;
+ increment_element(db, x);
+ }
+}
+
+
+void
+sql_update_unused_globals(sqlite3 *db, systemtap_session &s)
+{
+ // update db unused globals
+ for (unsigned i=0; i<s.unused_globals.size(); i++) {
+ struct source_loc place = s.unused_globals[i]->tok->location;
+ coverage_element x(place);
+
+ x.type = string("g");
+ x.name = s.unused_globals[i]->name;
+ x.removed = 1;
+ increment_element(db, x);
+ }
+}
+
+
+
+void update_coverage_db(systemtap_session &s)
+{
+ sqlite3 *db;
+ int rc;
+
+ string filename(s.data_path + "/" + s.kernel_release + ".db");
+
+ rc = sqlite3_open(filename.c_str(), &db);
+ if( rc ){
+ cerr << "Can't open database: " << sqlite3_errmsg(db) << endl;
+ sqlite3_close(db);
+ exit(EXIT_FAILURE);
+ }
+
+ string create_table("create table if not exists counts ("
+ "file text, line integer, col integer, "
+ "type text, name text, parent text, "
+ "compiled integer, removed integer, executed integer, "
+ "primary key (file, line, col))"
+ );
+
+ // lock the database
+ sql_stmt(db, "begin");
+
+ // update the number counts on things
+ sql_stmt(db, create_table.c_str());
+
+ if (s.verbose >2)
+ print_coverage_info(s);
+
+ sql_update_used_probes(db, s);
+ sql_update_unused_probes(db, s);
+ sql_update_used_functions(db, s);
+ sql_update_unused_functions(db, s);
+ sql_update_used_globals(db, s);
+ sql_update_unused_globals(db, s);
+
+ // unlock the database and close database
+ sql_stmt(db, "commit");
+
+ sqlite3_close(db);
+}
diff --git a/coveragedb.h b/coveragedb.h
new file mode 100644
index 00000000..5b62ba8b
--- /dev/null
+++ b/coveragedb.h
@@ -0,0 +1,70 @@
+// coveragedb.cxx
+// Copyright (C) 2007 Red Hat Inc.
+//
+// This file is part of systemtap, and is free software. You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+#ifndef COVERAGEDB_H
+#define COVERAGEDB_H
+
+#include "session.h"
+
+#include <string>
+
+
+/*
+
+tuples: file, line number, column, type of object, name
+values: number of times object "pulled_in", number of times "removed",
+times executed
+
+if (compiled == 0) object never compiled
+if (compiled > 0) object compiled
+if (removed > 0) object parsed
+if (executed == 0) never executed
+if (executed > 0) executed
+
+
+Want to make sure that the data base accurately reflects testing.
+1) atomic updates, either commit all or none of information
+2) only update coverage db compile info, if compile successful
+3) only update coverage db execute info, if instrumentation run suscessfully
+
+
+Would like to have something that looks for interesting features in db:
+
+list which things are not compile
+list which things are not exectuted
+
+ratio of compiled/total (overall, by file, by line)
+ratio of executed/total (overall, by file, by line)
+
+*/
+
+class coverage_element {
+public:
+ std::string file;
+ int line;
+ int col;
+ std::string type;
+ std::string name;
+ std::string parent;
+ int compiled;
+ int removed;
+ int executed;
+
+ coverage_element() { line = 0; col = 0;
+ compiled = 0; removed = 0; executed = 0; }
+
+ coverage_element(source_loc &place) {
+ file = place.file; line = place.line; col = place.column;
+ compiled = 0; removed = 0; executed = 0; }
+};
+
+void print_coverage_info(systemtap_session &s);
+void update_coverage_db(systemtap_session &s);
+
+#endif
+
diff --git a/elaborate.cxx b/elaborate.cxx
index 82d2a5d9..0bd1c3eb 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -96,6 +96,14 @@ derived_probe::printsig_nested (ostream& o) const
}
+void
+derived_probe::collect_derivation_chain (std::vector<derived_probe*> &probes_list)
+{
+ probes_list.push_back(this);
+ base->collect_derivation_chain(probes_list);
+}
+
+
probe_point*
derived_probe::sole_location () const
{
@@ -424,9 +432,9 @@ alias_expansion_builder
// The new probe gets the location list of the alias,
n->locations = alias->locations;
- // the token location of the use,
- n->tok = use->tok;
- n->body->tok = use->tok;
+ // the token location of the alias,
+ n->tok = location->tok;
+ n->body->tok = location->tok;
// and statements representing the concatenation of the alias'
// body with the use's.
@@ -1367,6 +1375,9 @@ void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p)
if (s.verbose>2)
clog << "Eliding unused function " << s.functions[i]->name
<< endl;
+ if (s.tapset_compile_coverage) {
+ s.unused_functions.push_back (s.functions[i]);
+ }
s.functions.erase (s.functions.begin() + i);
relaxed_p = false;
// NB: don't increment i
@@ -1407,6 +1418,10 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
if (s.verbose>2)
clog << "Eliding unused local variable "
<< l->name << " in " << s.probes[i]->name << endl;
+ if (s.tapset_compile_coverage) {
+ s.probes[i]->unused_locals.push_back
+ (s.probes[i]->locals[j]);
+ }
s.probes[i]->locals.erase(s.probes[i]->locals.begin() + j);
relaxed_p = false;
// don't increment j
@@ -1425,6 +1440,10 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
clog << "Eliding unused local variable "
<< l->name << " in function " << s.functions[i]->name
<< endl;
+ if (s.tapset_compile_coverage) {
+ s.functions[i]->unused_locals.push_back
+ (s.functions[i]->locals[j]);
+ }
s.functions[i]->locals.erase(s.functions[i]->locals.begin() + j);
relaxed_p = false;
// don't increment j
@@ -1441,6 +1460,9 @@ void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
if (s.verbose>2)
clog << "Eliding unused global variable "
<< l->name << endl;
+ if (s.tapset_compile_coverage) {
+ s.unused_globals.push_back(s.globals[i]);
+ }
s.globals.erase(s.globals.begin() + i);
relaxed_p = false;
// don't increment i
diff --git a/elaborate.h b/elaborate.h
index ec49e126..6967e1e7 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -118,6 +118,7 @@ struct derived_probe: public probe
virtual probe_point* sole_location () const;
virtual void printsig (std::ostream &o) const;
void printsig_nested (std::ostream &o) const;
+ virtual void collect_derivation_chain (std::vector<derived_probe*> &probes_list);
virtual void emit_probe_context_vars (translator_output*) {}
// From within unparser::emit_common_header, add any extra variables
diff --git a/main.cxx b/main.cxx
index f5740aa9..53f47513 100644
--- a/main.cxx
+++ b/main.cxx
@@ -18,6 +18,7 @@
#include "hash.h"
#include "cache.h"
#include "util.h"
+#include "coveragedb.h"
#include <iostream>
#include <fstream>
@@ -99,6 +100,8 @@ usage (systemtap_session& s, int exitcode)
<< endl
<< " -x PID sets target() to PID" << endl
<< " -t collect probe timing information" << endl
+ << " -q generate information on tapset coverage"
+ << endl
;
// -d: dump safety-related external references
@@ -216,6 +219,7 @@ main (int argc, char * const argv [])
s.perfmon=0;
s.symtab = false;
s.use_cache = true;
+ s.tapset_compile_coverage = false;
const char* s_p = getenv ("SYSTEMTAP_TAPSET");
if (s_p != NULL)
@@ -262,10 +266,14 @@ main (int argc, char * const argv [])
}
}
+ const char* s_tc = getenv ("SYSTEMTAP_COVERAGE");
+ if (s_tc != NULL)
+ s.tapset_compile_coverage = true;
+
while (true)
{
// NB: also see find_hash(), help(), switch stmt below, stap.1 man page
- int grc = getopt (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:u");
+ int grc = getopt (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uq");
if (grc < 0)
break;
switch (grc)
@@ -402,6 +410,10 @@ main (int argc, char * const argv [])
s.macros.push_back (string (optarg));
break;
+ case 'q':
+ s.tapset_compile_coverage = true;
+ break;
+
case 'h':
usage (s, 0);
break;
@@ -787,6 +799,12 @@ pass_5:
// if (rc) goto cleanup;
cleanup:
+
+ // update the database information
+ if (!rc && s.tapset_compile_coverage) {
+ update_coverage_db(s);
+ }
+
// Clean up temporary directory. Obviously, be careful with this.
if (s.tmpdir == "")
; // do nothing
diff --git a/session.h b/session.h
index f6ca3a43..638e9f27 100644
--- a/session.h
+++ b/session.h
@@ -97,6 +97,7 @@ struct systemtap_session
unsigned perfmon;
bool symtab; /* true: emit symbol table at translation time; false: let staprun do it. */
bool prologue_searching;
+ bool tapset_compile_coverage;
// Cache data
bool use_cache;
@@ -122,6 +123,10 @@ struct systemtap_session
std::vector<derived_probe*> probes; // see also *_probes groups below
std::vector<embeddedcode*> embeds;
std::map<std::string, statistic_decl> stat_decls;
+ // track things that are removed
+ std::vector<vardecl*> unused_globals;
+ std::vector<derived_probe*> unused_probes; // see also *_probes groups below
+ std::vector<functiondecl*> unused_functions;
// XXX: vector<*> instead please?
// Every probe in these groups must also appear in the
diff --git a/staptree.cxx b/staptree.cxx
index 08b2abae..3a50ac14 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -15,6 +15,7 @@
#include <typeinfo>
#include <sstream>
#include <cassert>
+#include <vector>
#include <algorithm>
using namespace std;
@@ -848,6 +849,13 @@ void probe::printsig (ostream& o) const
}
+void
+probe::collect_derivation_chain (std::vector<derived_probe*> &probes_list)
+{
+ probes_list.push_back((derived_probe*)this);
+}
+
+
void probe_point::print (ostream& o) const
{
for (unsigned i=0; i<components.size(); i++)
@@ -860,6 +868,23 @@ void probe_point::print (ostream& o) const
}
if (optional)
o << "?";
+ o << "{" << tok->location << "}\n";
+}
+
+string probe_point::str ()
+{
+ ostringstream o;
+ for (unsigned i=0; i<components.size(); i++)
+ {
+ if (i>0) o << ".";
+ probe_point::component* c = components[i];
+ o << c->functor;
+ if (c->arg)
+ o << "(" << *c->arg << ")";
+ }
+ if (optional)
+ o << "?";
+ return o.str();
}
diff --git a/staptree.h b/staptree.h
index 0ba8c657..415d510b 100644
--- a/staptree.h
+++ b/staptree.h
@@ -411,6 +411,7 @@ struct functiondecl: public symboldecl
{
std::vector<vardecl*> formal_args;
std::vector<vardecl*> locals;
+ std::vector<vardecl*> unused_locals;
statement* body;
functiondecl ();
void print (std::ostream& o) const;
@@ -537,6 +538,7 @@ struct next_statement: public statement
struct probe;
+struct derived_probe;
struct probe_alias;
struct embeddedcode;
struct stapfile
@@ -570,6 +572,7 @@ struct probe_point
void print (std::ostream& o) const;
probe_point ();
probe_point(std::vector<component*> const & comps,const token * t);
+ std::string str();
};
std::ostream& operator << (std::ostream& o, const probe_point& k);
@@ -581,9 +584,11 @@ struct probe
block* body;
const token* tok;
std::vector<vardecl*> locals;
+ std::vector<vardecl*> unused_locals;
probe ();
void print (std::ostream& o) const;
virtual void printsig (std::ostream &o) const;
+ virtual void collect_derivation_chain (std::vector<derived_probe*> &probes_list);
virtual probe* basest () { return this; }
virtual ~probe() {}
bool privileged;
diff --git a/systemtap.spec.in b/systemtap.spec.in
index ad58df0b..7f11b63a 100644
--- a/systemtap.spec.in
+++ b/systemtap.spec.in
@@ -39,6 +39,7 @@ Requires: kernel >= 2.6.9-11
BuildRequires: glib2-devel >= 2.0.0
# make check
BuildRequires: dejagnu
+BuildRequires: sqlite-devel
Requires: glib2 >= 2.0.0
# Requires: kernel-devel
# or is that kernel-smp-devel? kernel-hugemem-devel?
@@ -46,6 +47,7 @@ Requires: gcc make
# Suggest: kernel-debuginfo
Requires: systemtap-runtime = %{version}-%{release}
Requires: sudo
+Requires: sqlite
%if %{bundled_elfutils}
Source1: elfutils-%{elfutils_version}.tar.gz