summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog35
-rw-r--r--buildrun.cxx141
-rw-r--r--elaborate.cxx311
-rw-r--r--main.cxx24
-rw-r--r--parse.cxx35
-rw-r--r--session.h2
-rw-r--r--stap.1.in20
-rw-r--r--stapfuncs.5.in6
-rw-r--r--staptree.cxx149
-rw-r--r--staptree.h49
-rw-r--r--tapset/logging.stp6
-rw-r--r--tapsets.cxx83
-rwxr-xr-xtestsuite/semko/eleven.stp12
-rwxr-xr-xtestsuite/semko/thirty.stp2
-rwxr-xr-xtestsuite/semko/thirtyone.stp2
-rwxr-xr-xtestsuite/semko/twenty.stp2
-rwxr-xr-xtestsuite/semko/twentyfive.stp2
-rwxr-xr-xtestsuite/semko/twentyfour.stp2
-rwxr-xr-xtestsuite/semko/twentynine.stp4
-rwxr-xr-xtestsuite/semko/twentyseven.stp2
-rwxr-xr-xtestsuite/semko/twentysix.stp2
-rwxr-xr-xtestsuite/semok/optimize.stp18
-rwxr-xr-xtestsuite/transko/one.stp4
-rwxr-xr-xtestsuite/transok/five.stp2
-rw-r--r--translate.cxx48
25 files changed, 726 insertions, 237 deletions
diff --git a/ChangeLog b/ChangeLog
index 5b08d0f7..9495abd4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2006-01-24 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 2060 etc.
+ * tapsets.cxx (visit_target_symbol): Tolerate failed resolution by
+ letting target_symbol instance pass through to optimizer and
+ type checker.
+ * elaborate.cxx (semantic_pass_optimize): New family of functions and
+ associated visitor classes.
+ (visit_for_loop): Tolerate absent init/incr clauses.
+ (semantic_pass): Invoke unless unoptimized (-u) option given.
+ * main.cxx, session.h: Add support for flag.
+ * staptree.cxx (visit_for_loop): Tolerate absent init/incr clauses.
+ (traversing_visitor::visit_arrayindex): Visit the index expressions.
+ (functioncall_traversing_visitor): New class.
+ (varuse_tracking_visitor): New class.
+ * staptree.h: Corresponding changes.
+ * parse.cxx (parse_for_loop): Represent absent init/incr expressions
+ with null statement pointer instead of optimized-out dummy numbers.
+ * stap.1.in: Document optimization.
+ * testsuite/{semko,transko}/*.stp: Added "-u" or other code to many
+ tests to check bad code without optimizer elision.
+ * testsuite/semok/optimize.stp: New test.
+
+ * elaborate.cxx (unresolved, invalid, mismatch): Standardize error
+ message wording.
+ * stapfuncs.5.in: Tweak print/printf docs.
+ * tapset/logging.stp: Remove redundant "print" auxiliary function,
+ since it's a translator built-in.
+ * testsuite/transok/five.stp: Extend test.
+ * translate.cxx (emit_symbol_data): Put symbol table into a separate
+ temporary header file, to make "-p3" output easier on the eyes.
+ * buildrun.cxx (compile_pass): Eliminate test-mode support throughout.
+ * main.cxx, session.h, translate.cxx: Ditto.
+ * main.cxx (main): For last-pass=2 runs, print post-optimization ASTs.
+
2006-01-18 Josh Stone <joshua.i.stone@intel.com>
* tapsets.cxx (profile_derived_probe::emit_probe_entries): Setup
diff --git a/buildrun.cxx b/buildrun.cxx
index d678e874..744ff988 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -69,69 +69,34 @@ compile_pass (systemtap_session& s)
// XXX
// o << "CFLAGS += -ftime-report" << endl;
- if (s.test_mode)
- {
- string module_dir = string("/lib/modules/")
- + s.kernel_release + "/build";
-
- o << "CFLAGS += -I \"" << module_dir << "/include\"" << endl;
- o << "CFLAGS += -I \"" << s.runtime_path << "/user\"" << endl;
- o << "CFLAGS += -I \"" << s.runtime_path << "\"" << endl;
- o << "CFLAGS += -I \"" << module_dir << "/include/asm/mach-default\"" << endl;
- o << s.module_name << ": " << s.translated_source << endl;
- o << "\t$(CC) $(CFLAGS) -o " << s.module_name
- << " " << s.translated_source << endl;
- }
- else
- {
- // Assumes linux 2.6 kbuild
- o << "CFLAGS += -Wno-unused -Werror" << endl;
- o << "CFLAGS += -I \"" << s.runtime_path << "\"" << endl;
- o << "CFLAGS += -I \"" << s.runtime_path << "/relayfs\"" << endl;
- o << "obj-m := " << s.module_name << ".o" << endl;
- }
+ // Assumes linux 2.6 kbuild
+ o << "CFLAGS += -Wno-unused -Werror" << endl;
+ o << "CFLAGS += -I \"" << s.runtime_path << "\"" << endl;
+ o << "CFLAGS += -I \"" << s.runtime_path << "/relayfs\"" << endl;
+ o << "obj-m := " << s.module_name << ".o" << endl;
o.close ();
// Run make
- if (s.test_mode)
- {
- string make_cmd = string("make -C \"") + s.tmpdir + "\"";
-
- if (s.verbose)
- make_cmd += " V=1";
- else
- make_cmd += " -s >/dev/null 2>&1";
-
- if (s.verbose) clog << "Running " << make_cmd << endl;
- rc = system (make_cmd.c_str());
-
- if (s.verbose) clog << "Pass 4: compiled into \""
- << s.module_name
- << "\"" << endl;
- }
+ string module_dir = string("/lib/modules/")
+ + s.kernel_release + "/build";
+ string make_cmd = string("make")
+ + string (" -C \"") + module_dir + string("\"");
+ make_cmd += string(" M=\"") + s.tmpdir + string("\" modules");
+
+ if (s.verbose)
+ make_cmd += " V=1";
else
- {
- string module_dir = string("/lib/modules/")
- + s.kernel_release + "/build";
- string make_cmd = string("make")
- + string (" -C \"") + module_dir + string("\"");
- make_cmd += string(" M=\"") + s.tmpdir + string("\" modules");
-
- if (s.verbose)
- make_cmd += " V=1";
- else
- make_cmd += " -s >/dev/null 2>&1";
-
- if (s.verbose) clog << "Running " << make_cmd << endl;
- rc = system (make_cmd.c_str());
-
-
- if (s.verbose) clog << "Pass 4: compiled into \""
- << s.module_name << ".ko"
- << "\"" << endl;
- }
-
+ make_cmd += " -s >/dev/null 2>&1";
+
+ if (s.verbose) clog << "Running " << make_cmd << endl;
+ rc = system (make_cmd.c_str());
+
+
+ if (s.verbose) clog << "Pass 4: compiled into \""
+ << s.module_name << ".ko"
+ << "\"" << endl;
+
return rc;
}
@@ -141,41 +106,31 @@ run_pass (systemtap_session& s)
{
int rc = 0;
- if (s.test_mode)
- {
- string run_cmd = s.tmpdir + "/" + s.module_name;
-
- if (s.verbose) clog << "Running " << run_cmd << endl;
- rc = system (run_cmd.c_str ());
- }
- else // real run
- {
- // for now, just spawn stpd
- string stpd_cmd = string("sudo ")
- + string(PKGLIBDIR) + "/stpd "
- + (s.bulk_mode ? "" : "-r ")
- + (s.verbose ? "" : "-q ")
- + (s.output_file.empty() ? "" : "-o " + s.output_file + " ");
-
- stpd_cmd += "-d " + stringify(getpid()) + " ";
-
- if (s.cmd != "")
- stpd_cmd += "-c \"" + s.cmd + "\" ";
-
- if (s.target_pid)
- stpd_cmd += "-t " + stringify(s.target_pid) + " ";
-
- if (s.buffer_size)
- stpd_cmd += "-b " + stringify(s.buffer_size) + " ";
-
- stpd_cmd += s.tmpdir + "/" + s.module_name + ".ko";
-
- if (s.verbose) clog << "Running " << stpd_cmd << endl;
-
- signal (SIGHUP, SIG_IGN);
- signal (SIGINT, SIG_IGN);
- rc = system (stpd_cmd.c_str ());
- }
+ // for now, just spawn stpd
+ string stpd_cmd = string("sudo ")
+ + string(PKGLIBDIR) + "/stpd "
+ + (s.bulk_mode ? "" : "-r ")
+ + (s.verbose ? "" : "-q ")
+ + (s.output_file.empty() ? "" : "-o " + s.output_file + " ");
+
+ stpd_cmd += "-d " + stringify(getpid()) + " ";
+
+ if (s.cmd != "")
+ stpd_cmd += "-c \"" + s.cmd + "\" ";
+
+ if (s.target_pid)
+ stpd_cmd += "-t " + stringify(s.target_pid) + " ";
+
+ if (s.buffer_size)
+ stpd_cmd += "-b " + stringify(s.buffer_size) + " ";
+
+ stpd_cmd += s.tmpdir + "/" + s.module_name + ".ko";
+
+ if (s.verbose) clog << "Running " << stpd_cmd << endl;
+
+ signal (SIGHUP, SIG_IGN);
+ signal (SIGINT, SIG_IGN);
+ rc = system (stpd_cmd.c_str ());
return rc;
}
diff --git a/elaborate.cxx b/elaborate.cxx
index 7fc9784e..613d85ae 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -751,6 +751,7 @@ semantic_pass_stats (systemtap_session & sess)
static int semantic_pass_symbols (systemtap_session&);
+static int semantic_pass_optimize (systemtap_session&);
static int semantic_pass_types (systemtap_session&);
static int semantic_pass_vars (systemtap_session&);
static int semantic_pass_stats (systemtap_session&);
@@ -851,6 +852,7 @@ semantic_pass (systemtap_session& s)
register_standard_tapsets(s);
rc = semantic_pass_symbols (s);
+ if (rc == 0 && ! s.unoptimized) rc = semantic_pass_optimize (s);
if (rc == 0) rc = semantic_pass_types (s);
if (rc == 0) rc = semantic_pass_vars (s);
if (rc == 0) rc = semantic_pass_stats (s);
@@ -1172,6 +1174,300 @@ symresolution_info::find_function (const string& name, unsigned arity)
}
+
+// ------------------------------------------------------------------------
+// optimization
+
+
+// Do away with functiondecls that are never (transitively) called
+// from probes.
+void semantic_pass_opt1 (systemtap_session& s, bool& relaxed_p)
+{
+ functioncall_traversing_visitor ftv;
+ for (unsigned i=0; i<s.probes.size(); i++)
+ s.probes[i]->body->visit (& ftv);
+ for (unsigned i=0; i<s.functions.size(); /* see below */)
+ {
+ if (ftv.traversed.find(s.functions[i]) == ftv.traversed.end())
+ {
+ if (s.verbose)
+ clog << "Eliding unused function " << s.functions[i]->name
+ << endl;
+ s.functions.erase (s.functions.begin() + i);
+ relaxed_p = false;
+ // NB: don't increment i
+ }
+ else
+ i++;
+ }
+}
+
+
+// ------------------------------------------------------------------------
+
+// Do away with local & global variables that are never
+// written nor read.
+void semantic_pass_opt2 (systemtap_session& s, bool& relaxed_p)
+{
+ varuse_collecting_visitor vut;
+
+ for (unsigned i=0; i<s.probes.size(); i++)
+ s.probes[i]->body->visit (& vut);
+ // NB: Since varuse_collecting_visitor also traverses down
+ // actually called functions, we don't need to explicitly
+ // iterate over them. Uncalled ones should have been pruned
+ // in _opt1 above.
+ //
+ // for (unsigned i=0; i<s.functions.size(); i++)
+ // s.functions[i]->body->visit (& vut);
+
+ // Now in vut.read/written, we have a mixture of all locals, globals
+
+ for (unsigned i=0; i<s.probes.size(); i++)
+ for (unsigned j=0; j<s.probes[i]->locals.size(); /* see below */)
+ {
+ vardecl* l = s.probes[i]->locals[j];
+ if (vut.read.find (l) == vut.read.end() &&
+ vut.written.find (l) == vut.written.end())
+ {
+ if (s.verbose)
+ clog << "Eliding unused local variable "
+ << l->name << " in probe #" << i << endl;
+ s.probes[i]->locals.erase(s.probes[i]->locals.begin() + j);
+ relaxed_p = false;
+ // don't increment j
+ }
+ else
+ j++;
+ }
+ for (unsigned i=0; i<s.functions.size(); i++)
+ for (unsigned j=0; j<s.functions[i]->locals.size(); /* see below */)
+ {
+ vardecl* l = s.functions[i]->locals[j];
+ if (vut.read.find (l) == vut.read.end() &&
+ vut.written.find (l) == vut.written.end())
+ {
+ if (s.verbose)
+ clog << "Eliding unused local variable "
+ << l->name << " in function " << s.functions[i]->name
+ << endl;
+ s.functions[i]->locals.erase(s.functions[i]->locals.begin() + j);
+ relaxed_p = false;
+ // don't increment j
+ }
+ else
+ j++;
+ }
+ for (unsigned i=0; i<s.globals.size(); /* see below */)
+ {
+ vardecl* l = s.globals[i];
+ if (vut.read.find (l) == vut.read.end() &&
+ vut.written.find (l) == vut.written.end())
+ {
+ if (s.verbose)
+ clog << "Eliding unused global variable "
+ << l->name << endl;
+ s.globals.erase(s.globals.begin() + i);
+ relaxed_p = false;
+ // don't increment i
+ }
+ else
+ i++;
+ }
+}
+
+
+// ------------------------------------------------------------------------
+
+struct dead_assignment_remover: public traversing_visitor
+{
+ systemtap_session& session;
+ bool& relaxed_p;
+ const varuse_collecting_visitor& vut;
+ expression** current_expr;
+
+ dead_assignment_remover(systemtap_session& s, bool& r,
+ const varuse_collecting_visitor& v):
+ session(s), relaxed_p(r), vut(v), current_expr(0) {}
+
+ void visit_expr_statement (expr_statement* s);
+ // XXX: and other places where an assignment may be nested
+
+ void visit_assignment (assignment* e);
+};
+
+
+void
+dead_assignment_remover::visit_expr_statement (expr_statement* s)
+{
+ expression** last_expr = current_expr;
+ current_expr = & s->value;
+ s->value->visit (this);
+ current_expr = last_expr;
+}
+
+
+void
+dead_assignment_remover::visit_assignment (assignment* e)
+{
+ symbol* left = get_symbol_within_expression (e->left);
+ vardecl* leftvar = left->referent;
+ if (*current_expr == e) // we're not nested any deeper than expected
+ {
+ // clog << "Checking assignment to " << leftvar->name << " at " << *e->tok << endl;
+ if (vut.read.find(leftvar) == vut.read.end()) // var never read?
+ {
+ if (session.verbose)
+ clog << "Eliding assignment to " << leftvar->name
+ << " at " << *e->tok << endl;
+ *current_expr = e->right; // goodbye assignment*
+ relaxed_p = false;
+ }
+ }
+}
+
+
+// Let's remove assignments to variables that are never read. We
+// rewrite "(foo = expr)" as "(expr)". This makes foo a candidate to
+// be optimized away as an unused variable, and expr a candidate to be
+// removed as a side-effect-free statement expression. Wahoo!
+void semantic_pass_opt3 (systemtap_session& s, bool& relaxed_p)
+{
+ // Recompute the varuse data, which will probably match the opt2
+ // copy of the computation, except for those totally unused
+ // variables that opt2 removed.
+ varuse_collecting_visitor vut;
+ for (unsigned i=0; i<s.probes.size(); i++)
+ s.probes[i]->body->visit (& vut); // includes reachable functions too
+
+ dead_assignment_remover dar (s, relaxed_p, vut);
+ // This instance may be reused for multiple probe/function body trims.
+
+ for (unsigned i=0; i<s.probes.size(); i++)
+ s.probes[i]->body->visit (& dar);
+ for (unsigned i=0; i<s.functions.size(); i++)
+ s.functions[i]->body->visit (& dar);
+ // The rewrite operation is performed within the visitor.
+}
+
+
+// ------------------------------------------------------------------------
+
+struct dead_stmtexpr_remover: public traversing_visitor
+{
+ systemtap_session& session;
+ bool& relaxed_p;
+ statement** current_stmt; // pointer to current stmt* being iterated
+
+ dead_stmtexpr_remover(systemtap_session& s, bool& r):
+ session(s), relaxed_p(r), current_stmt(0) {}
+
+ void visit_block (block *s);
+ // XXX: and other places where stmt_expr's might be nested
+
+ void visit_expr_statement (expr_statement *s);
+};
+
+
+void
+dead_stmtexpr_remover::visit_block (block *s)
+{
+ for (unsigned i=0; i<s->statements.size(); i++)
+ {
+ statement** last_stmt = current_stmt;
+ current_stmt = & s->statements[i];
+ s->statements[i]->visit (this);
+ current_stmt = last_stmt;
+ }
+}
+
+
+void
+dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
+{
+ // Run a varuse query against the operand expression. If it has no
+ // side-effects, replace the entire statement expression by a null
+ // statement. This replacement is done by overwriting the
+ // current_stmt pointer.
+ //
+ // Unlike many other visitors, we do *not* traverse this outermost
+ // one into the expression subtrees. There is no need - no
+ // expr_statement nodes will be found there. (Function bodies
+ // need to be visited explicitly by our caller.)
+ //
+ // NB. While we don't share nodes in the parse tree, let's not
+ // deallocate *s anyway, just in case...
+
+ varuse_collecting_visitor vut;
+ s->value->visit (& vut);
+ if (vut.written.empty() && !vut.embedded_seen)
+ {
+ if (session.verbose)
+ clog << "Eliding side-effect-free expression "
+ << *s->tok << endl;
+
+ null_statement* ns = new null_statement;
+ ns->tok = s->tok;
+ * current_stmt = ns;
+ // XXX: A null_statement carries more weight in the translator's
+ // output than a nonexistent statement. It might be nice to
+ // work a little harder and completely eliminate all traces of
+ // an elided statement.
+
+ relaxed_p = false;
+ }
+}
+
+
+void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
+{
+ // Finally, let's remove some statement-expressions that have no
+ // side-effect. These should be exactly those whose private varuse
+ // visitors come back with an empty "written" and "embedded" lists.
+
+ dead_stmtexpr_remover duv (s, relaxed_p);
+ // This instance may be reused for multiple probe/function body trims.
+
+ for (unsigned i=0; i<s.probes.size(); i++)
+ s.probes[i]->body->visit (& duv);
+ for (unsigned i=0; i<s.functions.size(); i++)
+ s.functions[i]->body->visit (& duv);
+}
+
+
+static int
+semantic_pass_optimize (systemtap_session& s)
+{
+ // In this pass, we attempt to rewrite probe/function bodies to
+ // eliminate some blatantly unnecessary code. This is run before
+ // type inference, but after symbol resolution and derived_probe
+ // creation. We run an outer "relaxation" loop that repeats the
+ // optimizations until none of them find anything to remove.
+
+ int rc = 0;
+
+ bool relaxed_p = false;
+ while (! relaxed_p)
+ {
+ relaxed_p = true; // until proven otherwise
+
+ semantic_pass_opt1 (s, relaxed_p);
+ semantic_pass_opt2 (s, relaxed_p);
+ semantic_pass_opt3 (s, relaxed_p);
+ semantic_pass_opt4 (s, relaxed_p);
+ }
+
+ if (s.probes.size() == 0)
+ {
+ cerr << "semantic error: no probes found." << endl;
+ rc = 1;
+ }
+
+ return rc;
+}
+
+
+
// ------------------------------------------------------------------------
// type resolution
@@ -1568,6 +1864,11 @@ typeresolution_info::visit_symbol (symbol* e)
void
typeresolution_info::visit_target_symbol (target_symbol* e)
{
+ // This occurs only if a target symbol was not resolved over in
+ // tapset.cxx land, that error was properly suppressed, and the
+ // later unused-expression-elimination pass didn't get rid of it
+ // either. So we have a target symbol that is believed to be of
+ // genuine use, yet unresolved by the provider.
throw semantic_error("unresolved target-symbol expression", e->tok);
}
@@ -1730,11 +2031,11 @@ void
typeresolution_info::visit_for_loop (for_loop* e)
{
t = pe_unknown;
- e->init->visit (this);
+ if (e->init) e->init->visit (this);
t = pe_long;
e->cond->visit (this);
t = pe_unknown;
- e->incr->visit (this);
+ if (e->incr) e->incr->visit (this);
t = pe_unknown;
e->block->visit (this);
}
@@ -2056,7 +2357,7 @@ typeresolution_info::unresolved (const token* tok)
if (assert_resolvability)
{
- cerr << "error: unresolved type for ";
+ cerr << "semantic error: unresolved type for ";
if (tok)
cerr << *tok;
else
@@ -2073,7 +2374,7 @@ typeresolution_info::invalid (const token* tok, exp_type pe)
if (assert_resolvability)
{
- cerr << "error: invalid type " << pe << " for ";
+ cerr << "semantic error: invalid type " << pe << " for ";
if (tok)
cerr << *tok;
else
@@ -2090,7 +2391,7 @@ typeresolution_info::mismatch (const token* tok, exp_type t1, exp_type t2)
if (assert_resolvability)
{
- cerr << "error: type mismatch for ";
+ cerr << "semantic error: type mismatch for ";
if (tok)
cerr << *tok;
else
diff --git a/main.cxx b/main.cxx
index 648032d8..43486813 100644
--- a/main.cxx
+++ b/main.cxx
@@ -60,7 +60,7 @@ usage (systemtap_session& s)
<< " -h show help" << endl
<< " -V show version" << endl
<< " -k keep temporary directory" << endl
- // << " -t test mode" << (s.test_mode ? " [set]" : "") << endl
+ << " -u unoptimized translation" << (s.unoptimized ? " [set]" : "") << endl
<< " -g guru mode" << (s.guru_mode ? " [set]" : "") << endl
<< " -b bulk (relayfs) mode" << (s.bulk_mode ? " [set]" : "") << endl
<< " -s NUM buffer size in megabytes, instead of "
@@ -120,9 +120,9 @@ main (int argc, char * const argv [])
s.kernel_release = string (buf.release);
s.architecture = string (buf.machine);
s.verbose = false;
- s.test_mode = false;
s.guru_mode = false;
s.bulk_mode = false;
+ s.unoptimized = false;
s.buffer_size = 0;
s.last_pass = 5;
s.module_name = "stap_" + stringify(getpid());
@@ -145,7 +145,7 @@ main (int argc, char * const argv [])
while (true)
{
- int grc = getopt (argc, argv, "hVvp:I:e:o:tR:r:m:kgc:x:D:bs:");
+ int grc = getopt (argc, argv, "hVvp:I:e:o:R:r:m:kgc:x:D:bs:u");
if (grc < 0)
break;
switch (grc)
@@ -182,10 +182,6 @@ main (int argc, char * const argv [])
s.output_file = string (optarg);
break;
- case 't':
- s.test_mode = true;
- break;
-
case 'R':
s.runtime_path = string (optarg);
break;
@@ -210,6 +206,10 @@ main (int argc, char * const argv [])
s.bulk_mode = true;
break;
+ case 'u':
+ s.unoptimized = true;
+ break;
+
case 's':
s.buffer_size = atoi (optarg);
if (s.buffer_size < 1 || s.buffer_size > 64)
@@ -415,6 +415,11 @@ main (int argc, char * const argv [])
v->printsig (cout);
cout << endl;
}
+ if (s.verbose)
+ {
+ f->body->print (cout);
+ cout << endl;
+ }
}
if (s.probes.size() > 0)
@@ -433,6 +438,11 @@ main (int argc, char * const argv [])
v->printsig (cout);
cout << endl;
}
+ if (s.verbose)
+ {
+ p->body->print (cout);
+ cout << endl;
+ }
}
}
diff --git a/parse.cxx b/parse.cxx
index 56495a56..1d8e2947 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -1232,11 +1232,8 @@ parser::parse_for_loop ()
t = peek ();
if (t && t->type == tok_operator && t->content == ";")
{
- literal_number* l = new literal_number(0);
- expr_statement* es = new expr_statement;
- es->value = l;
- s->init = es;
- es->value->tok = es->tok = next ();
+ s->init = 0;
+ next ();
}
else
{
@@ -1266,11 +1263,8 @@ parser::parse_for_loop ()
t = peek ();
if (t && t->type == tok_operator && t->content == ")")
{
- literal_number* l = new literal_number(2);
- expr_statement* es = new expr_statement;
- es->value = l;
- s->incr = es;
- es->value->tok = es->tok = next ();
+ s->incr = 0;
+ next ();
}
else
{
@@ -1301,23 +1295,12 @@ parser::parse_while_loop ()
throw parse_error ("expected '('");
// dummy init and incr fields
- literal_number* l = new literal_number(0);
- expr_statement* es = new expr_statement;
- es->value = l;
- s->init = es;
- es->value->tok = es->tok = t;
-
- l = new literal_number(2);
- es = new expr_statement;
- es->value = l;
- s->incr = es;
- es->value->tok = es->tok = t;
-
+ s->init = 0;
+ s->incr = 0;
// condition
s->cond = parse_expression ();
-
t = next ();
if (! (t->type == tok_operator && t->content == ")"))
throw parse_error ("expected ')'");
@@ -1808,6 +1791,12 @@ parser::parse_unary ()
expression*
parser::parse_crement () // as in "increment" / "decrement"
{
+ // NB: Ideally, we'd parse only a symbol as an operand to the
+ // *crement operators, instead of a general expression value. We'd
+ // need more complex lookahead code to tell apart the postfix cases.
+ // So we just punt, and leave it to pass-3 to signal errors on
+ // cases like "4++".
+
const token* t = peek ();
if (t && t->type == tok_operator
&& (t->content == "++" || t->content == "--"))
diff --git a/session.h b/session.h
index 0c9a0082..563947b6 100644
--- a/session.h
+++ b/session.h
@@ -69,11 +69,11 @@ struct systemtap_session
std::string cmd;
int target_pid;
int last_pass;
- bool test_mode;
bool verbose;
bool keep_tmpdir;
bool guru_mode;
bool bulk_mode;
+ bool unoptimized;
int buffer_size;
// temporary directory for module builds etc.
diff --git a/stap.1.in b/stap.1.in
index d37060eb..3bc9368e 100644
--- a/stap.1.in
+++ b/stap.1.in
@@ -72,7 +72,7 @@ prints a list of supported options.
.\" -t test mode
.TP
.B \-v
-Verbose mode. Produces more informative output.
+Verbose mode. Produce more informative output.
.TP
.B \-h
Show help message.
@@ -86,9 +86,12 @@ in order to examine the generated C code, or to reuse the compiled
kernel object.
.TP
.B \-g
-Guru mode. Enables parsing of unsafe expert-level constructs like
+Guru mode. Enable parsing of unsafe expert-level constructs like
embedded C.
.TP
+.B \-u
+Unoptimized mode. Disable unused code elision during elaboration.
+.TP
.BI \-b
Use relayfs-based bulk mode for kernel-to-user data transfer.
.TP
@@ -583,11 +586,11 @@ and all scripts (files named
.IR *.stp )
found in a tapset directory. The directories listed
with
-.BR -I
+.BR \-I
are processed in sequence, each processed in "guru mode". For each
directory, a number of subdirectories are also searched. These
subdirectories are derived from the selected kernel version (the
-.BR -R
+.BR \-R
option),
in order to allow more kernel-version-specific scripts to override less
specific ones. For example, for a kernel version
@@ -617,6 +620,15 @@ appropriate kernel debugging information to be installed. In the
associated probe handlers, target-side variables (whose names begin
with "$") are found and have their run-time locations decoded.
.PP
+Next, all probes and functions are analyzed for optimization
+opportunities, in order to remove variables, expressions, and
+functions that have no useful value and no side-effect. Since this
+process can hide latent code errors such as type mismatches or invalid
+$target variables, it sometimes may be useful to disable the
+optimizations with the
+.BR \-u
+option.
+.PP
Finally, all variable, function, parameter, array, and index types are
inferred from context (literals and operators). Stopping the
translator after pass 2 causes it to list all the probes, functions,
diff --git a/stapfuncs.5.in b/stapfuncs.5.in
index 56d6aed5..f68f462d 100644
--- a/stapfuncs.5.in
+++ b/stapfuncs.5.in
@@ -31,9 +31,9 @@ Log the given string to the common trace buffer. Append an implicit
end-of-line.
.TP
-print:unknown (msg:string)
-print:unknown (k:long)
-Print the given integer or string to the common trace buffer.
+print:unknown (...)
+Print the given integer, string, or statistics value to
+the common trace buffer.
.TP
printf:unknown (fmt:string, ...)
diff --git a/staptree.cxx b/staptree.cxx
index 0eb898ac..97b4bcc1 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -691,11 +691,11 @@ void block::print (ostream& o) const
void for_loop::print (ostream& o) const
{
o << "for (";
- init->print (o);
+ if (init) init->print (o);
o << "; ";
cond->print (o);
o << "; ";
- incr->print (o);
+ if (incr) incr->print (o);
o << ") ";
block->print (o);
}
@@ -1262,9 +1262,9 @@ traversing_visitor::visit_if_statement (if_statement* s)
void
traversing_visitor::visit_for_loop (for_loop* s)
{
- s->init->visit (this);
+ if (s->init) s->init->visit (this);
s->cond->visit (this);
- s->incr->visit (this);
+ if (s->incr) s->incr->visit (this);
s->block->visit (this);
}
@@ -1409,6 +1409,9 @@ traversing_visitor::visit_target_symbol (target_symbol* e)
void
traversing_visitor::visit_arrayindex (arrayindex* e)
{
+ for (unsigned i=0; i<e->indexes.size(); i++)
+ e->indexes[i]->visit (this);
+
symbol *array = NULL;
hist_op *hist = NULL;
classify_indexable(e->base, array, hist);
@@ -1416,8 +1419,6 @@ traversing_visitor::visit_arrayindex (arrayindex* e)
return array->visit(this);
else
return hist->visit(this);
- for (unsigned i=0; i<e->indexes.size(); i++)
- e->indexes[i]->visit (this);
}
void
@@ -1449,6 +1450,142 @@ traversing_visitor::visit_hist_op (hist_op* e)
}
+void
+functioncall_traversing_visitor::visit_functioncall (functioncall* e)
+{
+ traversing_visitor::visit_functioncall (e);
+
+ // prevent infinite recursion
+ if (traversed.find (e->referent) == traversed.end ())
+ {
+ traversed.insert (e->referent);
+ // recurse
+ e->referent->body->visit (this);
+ }
+}
+
+
+void
+varuse_collecting_visitor::visit_embeddedcode (embeddedcode *s)
+{
+ embedded_seen = true;
+}
+
+
+void
+varuse_collecting_visitor::visit_print_format (print_format* e)
+{
+ // NB: Instead of being top-level statements, "print" and "printf"
+ // are implemented as statement-expressions containing a
+ // print_format. They have side-effects, but not via the
+ // embedded-code detection method above.
+ embedded_seen = true;
+ functioncall_traversing_visitor::visit_print_format (e);
+}
+
+
+void
+varuse_collecting_visitor::visit_assignment (assignment *e)
+{
+ if (e->op == "=" || e->op == "<<<") // pure writes
+ {
+ expression* last_lvalue = current_lrvalue;
+ current_lvalue = e->left; // leave a mark for ::visit_symbol
+ functioncall_traversing_visitor::visit_assignment (e);
+ current_lvalue = last_lvalue;
+ }
+ else // read-modify-writes
+ {
+ expression* last_lrvalue = current_lrvalue;
+ current_lrvalue = e->left; // leave a mark for ::visit_symbol
+ functioncall_traversing_visitor::visit_assignment (e);
+ current_lrvalue = last_lrvalue;
+ }
+}
+
+void
+varuse_collecting_visitor::visit_symbol (symbol *e)
+{
+ if (e->referent == 0)
+ throw semantic_error ("symbol without referent", e->tok);
+
+ if (current_lvalue == e || current_lrvalue == e)
+ {
+ written.insert (e->referent);
+ // clog << "write ";
+ }
+ if (current_lvalue != e || current_lrvalue == e)
+ {
+ read.insert (e->referent);
+ // clog << "read ";
+ }
+ // clog << *e->tok << endl;
+}
+
+// NB: stat_op need not be overridden, since it will get to
+// visit_symbol and only as a possible rvalue.
+
+void
+varuse_collecting_visitor::visit_arrayindex (arrayindex *e)
+{
+ // Hooking this callback is necessary because of the hacky
+ // statistics representation. For the expression "i[4] = 5", the
+ // incoming lvalue will point to this arrayindex. However, the
+ // symbol corresponding to the "i[4]" is multiply inherited with
+ // arrayindex. If the symbol base part of this object is not at
+ // offset 0, then static_cast<symbol*>(e) may result in a different
+ // address, and not match lvalue by number when we recurse that way.
+ // So we explicitly override the incoming lvalue/lrvalue values to
+ // point at the embedded objects' actual base addresses.
+
+ expression* last_lrvalue = current_lrvalue;
+ expression* last_lvalue = current_lvalue;
+
+ symbol *array = NULL;
+ hist_op *hist = NULL;
+ classify_indexable(e->base, array, hist);
+
+ if (array)
+ {
+ if (current_lrvalue == e) current_lrvalue = array;
+ if (current_lvalue == e) current_lvalue = array;
+ functioncall_traversing_visitor::visit_arrayindex (e);
+ }
+ else // if (hist)
+ {
+ if (current_lrvalue == e) current_lrvalue = hist->stat;
+ if (current_lvalue == e) current_lvalue = hist->stat;
+ functioncall_traversing_visitor::visit_arrayindex (e);
+ }
+
+ current_lrvalue = last_lrvalue;
+ current_lvalue = last_lvalue;
+}
+
+
+void
+varuse_collecting_visitor::visit_pre_crement (pre_crement *e)
+{
+ expression* last_lrvalue = current_lrvalue;
+ current_lrvalue = e->operand; // leave a mark for ::visit_symbol
+ functioncall_traversing_visitor::visit_pre_crement (e);
+ current_lrvalue = last_lrvalue;
+}
+
+void
+varuse_collecting_visitor::visit_post_crement (post_crement *e)
+{
+ expression* last_lrvalue = current_lrvalue;
+ current_lrvalue = e->operand; // leave a mark for ::visit_symbol
+ functioncall_traversing_visitor::visit_post_crement (e);
+ current_lrvalue = last_lrvalue;
+}
+
+
+
+
+
+
// ------------------------------------------------------------------------
diff --git a/staptree.h b/staptree.h
index 4b3eb996..fecd6aaf 100644
--- a/staptree.h
+++ b/staptree.h
@@ -12,6 +12,7 @@
#include "session.h"
#include <map>
#include <stack>
+#include <set>
#include <string>
#include <vector>
#include <iostream>
@@ -443,9 +444,9 @@ struct block: public statement
struct expr_statement;
struct for_loop: public statement
{
- expr_statement* init;
+ expr_statement* init; // may be 0
expression* cond;
- expr_statement* incr;
+ expr_statement* incr; // may be 0
statement* block;
void print (std::ostream& o) const;
void visit (visitor* u);
@@ -485,7 +486,7 @@ struct if_statement: public statement
{
expression* condition;
statement* thenblock;
- statement* elseblock;
+ statement* elseblock; // may be 0
void print (std::ostream& o) const;
void visit (visitor* u);
};
@@ -630,9 +631,9 @@ struct visitor
};
-// A default kind of visitor, which by default travels down
-// to the leaves of the statement/expression tree, up to
-// but excluding following vardecls (referent pointers).
+// A simple kind of visitor, which travels down to the leaves of the
+// statement/expression tree, up to but excluding following vardecls
+// and functioncalls.
struct traversing_visitor: public visitor
{
void visit_block (block *s);
@@ -670,6 +671,42 @@ struct traversing_visitor: public visitor
};
+// A kind of traversing visitor, which also follows function calls.
+// It uses an internal set object to prevent infinite recursion.
+struct functioncall_traversing_visitor: public traversing_visitor
+{
+ std::set<functiondecl*> traversed;
+ void visit_functioncall (functioncall* e);
+};
+
+
+// A kind of traversing visitor, which also follows function calls,
+// and stores the vardecl* referent of each variable read and/or
+// written and other such sundry side-effect data. It's used by
+// the elaboration-time optimizer pass.
+struct varuse_collecting_visitor: public functioncall_traversing_visitor
+{
+ std::set<vardecl*> read;
+ std::set<vardecl*> written;
+ bool embedded_seen;
+ expression* current_lvalue;
+ expression* current_lrvalue;
+ varuse_collecting_visitor():
+ embedded_seen (false),
+ current_lvalue(0),
+ current_lrvalue(0) {}
+ void visit_embeddedcode (embeddedcode *s);
+ void visit_print_format (print_format *e);
+ void visit_assignment (assignment *e);
+ void visit_arrayindex (arrayindex *e);
+ void visit_symbol (symbol *e);
+ void visit_pre_crement (pre_crement *e);
+ void visit_post_crement (post_crement *e);
+};
+
+
+
+
// A kind of visitor that throws an semantic_error exception
// whenever a non-overridden method is called.
struct throwing_visitor: public visitor
diff --git a/tapset/logging.stp b/tapset/logging.stp
index c9c60c8d..a3fcac04 100644
--- a/tapset/logging.stp
+++ b/tapset/logging.stp
@@ -6,11 +6,7 @@
// Public License (GPL); either version 2, or (at your option) any
// later version.
-function print (msg:string) %{
- _stp_print (THIS->msg);
-%}
-
-// like print but with a newline
+// send a string out with a newline
function log (msg:string) %{
_stp_printf ("%s\n", THIS->msg);
%}
diff --git a/tapsets.cxx b/tapsets.cxx
index 7d10ddf3..89201cb2 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -1868,46 +1868,48 @@ target_variable_flavour_calculating_visitor::visit_target_symbol (target_symbol
{
assert(e->base_name.size() > 0 && e->base_name[0] == '$');
- try
+ // NB: if for whatever reason this variable does not resolve,
+ // or is illegally used (write in non-guru mode for instance),
+ // just pretend that it's OK anyway. var_expanding_copy_visitor
+ // will take care of throwing the appropriate exception.
+
+ bool lvalue = is_active_lvalue(e);
+ flavour += lvalue ? 'w' : 'r';
+ exp_type ty;
+ string expr;
+ try
{
- bool lvalue = is_active_lvalue(e);
- if (lvalue && !q.sess.guru_mode)
- throw semantic_error("Writing to target variable outside of guru mode", e->tok);
-
- flavour += lvalue ? 'w' : 'r';
- exp_type ty;
- string expr = q.dw.literal_stmt_for_local(scope_die,
- addr,
- e->base_name.substr(1),
- e->components,
- lvalue,
- ty);
- switch (ty)
- {
- case pe_unknown:
- flavour += 'U';
- break;
- case pe_long:
- flavour += 'L';
- break;
- case pe_string:
- flavour += 'S';
- break;
- case pe_stats:
- flavour += 'T';
- break;
- }
- flavour += lex_cast<string>(expr.size());
- flavour += '{';
- flavour += expr;
- flavour += '}';
+ expr = q.dw.literal_stmt_for_local(scope_die,
+ addr,
+ e->base_name.substr(1),
+ e->components,
+ lvalue,
+ ty);
}
- catch (const semantic_error& er)
+ catch (const semantic_error& e)
{
- semantic_error er2 (er);
- er2.tok1 = e->tok;
- q.sess.print_error (er2);
+ ty = pe_unknown;
}
+
+ switch (ty)
+ {
+ case pe_unknown:
+ flavour += 'U';
+ break;
+ case pe_long:
+ flavour += 'L';
+ break;
+ case pe_string:
+ flavour += 'S';
+ break;
+ case pe_stats:
+ flavour += 'T';
+ break;
+ }
+ flavour += lex_cast<string>(expr.size());
+ flavour += '{';
+ flavour += expr;
+ flavour += '}';
}
@@ -2636,9 +2638,12 @@ var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
}
catch (const semantic_error& er)
{
- // No need to be verbose: the flavour-gathering visitor
- // already printed a message for this exact case.
- throw semantic_error ("due to failed target variable resolution");
+ // We suppress this error message, and pass the unresolved
+ // target_symbol to the next pass. We hope that this value ends
+ // up not being referenced after all, so it can be optimized out
+ // quietly.
+ provide <target_symbol*> (this, e);
+ return;
}
fdecl->name = fname;
diff --git a/testsuite/semko/eleven.stp b/testsuite/semko/eleven.stp
index 34dfa225..f76c2df9 100755
--- a/testsuite/semko/eleven.stp
+++ b/testsuite/semko/eleven.stp
@@ -1,15 +1,15 @@
-#! stap -p2
+#! stap -up2
global arr,rra
-
+global s,n
probe begin {
arr[0]="value"
rra["key"]=0
}
probe end {
# confirm that typechecking works the same way for all array indexing
- if (k in arr) { k.""; arr[k]+0 }
- foreach (l in arr) { l.""; arr[l]+0 }
- if (m in rra) { m+1; rra[m]."" }
- foreach (n in rra) { n+0; rra[n]."" }
+ if (k in arr) { s=k.""; i=arr[k]+0 }
+ foreach (l in arr) { s=l.""; i=arr[l]+0 }
+ if (m in rra) { i=m+1; s=rra[m]."" }
+ foreach (n in rra) { i=n+0; s=rra[n]."" }
}
diff --git a/testsuite/semko/thirty.stp b/testsuite/semko/thirty.stp
index b145f826..57278af0 100755
--- a/testsuite/semko/thirty.stp
+++ b/testsuite/semko/thirty.stp
@@ -1,4 +1,4 @@
-#! stap -p2
+#! stap -up2
# need one of these for each prohibited statistic operation
diff --git a/testsuite/semko/thirtyone.stp b/testsuite/semko/thirtyone.stp
index 0462d4d5..dcb4fa7e 100755
--- a/testsuite/semko/thirtyone.stp
+++ b/testsuite/semko/thirtyone.stp
@@ -1,4 +1,4 @@
-#! stap -p2
+#! stap -up2
# need one of these for each prohibited statistic operation
diff --git a/testsuite/semko/twenty.stp b/testsuite/semko/twenty.stp
index 899efdc1..df12fa36 100755
--- a/testsuite/semko/twenty.stp
+++ b/testsuite/semko/twenty.stp
@@ -3,5 +3,5 @@
function a:string () { }
probe begin {
- a() + 1
+ print (a() + 1)
}
diff --git a/testsuite/semko/twentyfive.stp b/testsuite/semko/twentyfive.stp
index 8758bb67..5eb3b570 100755
--- a/testsuite/semko/twentyfive.stp
+++ b/testsuite/semko/twentyfive.stp
@@ -1,4 +1,4 @@
-#! stap -p2
+#! stap -up2
# need one of these for each prohibited statistic operation
diff --git a/testsuite/semko/twentyfour.stp b/testsuite/semko/twentyfour.stp
index ae75bf31..da6979bb 100755
--- a/testsuite/semko/twentyfour.stp
+++ b/testsuite/semko/twentyfour.stp
@@ -1,4 +1,4 @@
-#! stap -p2
+#! stap -up2
# need one of these for each prohibited statistic operation
diff --git a/testsuite/semko/twentynine.stp b/testsuite/semko/twentynine.stp
index b26e9872..19c66225 100755
--- a/testsuite/semko/twentynine.stp
+++ b/testsuite/semko/twentynine.stp
@@ -1,4 +1,4 @@
-#! stap -p2
+#! stap -up2
# need one of these for each prohibited statistic operation
@@ -6,6 +6,6 @@ global x
probe end
{
- x <<< 10 <<< 11
+ x <<< 10 <<< 11 # but see PR 1922
}
diff --git a/testsuite/semko/twentyseven.stp b/testsuite/semko/twentyseven.stp
index 6c5bd4f9..287ebebf 100755
--- a/testsuite/semko/twentyseven.stp
+++ b/testsuite/semko/twentyseven.stp
@@ -1,4 +1,4 @@
-#! stap -p2
+#! stap -up2
# need one of these for each prohibited statistic operation
diff --git a/testsuite/semko/twentysix.stp b/testsuite/semko/twentysix.stp
index 9ebffa4a..dd4bce51 100755
--- a/testsuite/semko/twentysix.stp
+++ b/testsuite/semko/twentysix.stp
@@ -1,4 +1,4 @@
-#! stap -p2
+#! stap -up2
# need one of these for each prohibited statistic operation
diff --git a/testsuite/semok/optimize.stp b/testsuite/semok/optimize.stp
new file mode 100755
index 00000000..28ccb46c
--- /dev/null
+++ b/testsuite/semok/optimize.stp
@@ -0,0 +1,18 @@
+#! stap -p2
+
+# We count on the optimizer to blow away these ridiculous
+# expressions, since they have no effect on the output.
+
+global b
+
+function zoo (x) {
+ return "tada" + x
+}
+
+probe begin {
+ b <<< "hello"
+ a = b + 2
+ zoo (zoo (5))
+ b = "goodbye"
+ no . $such . $target + $variable
+}
diff --git a/testsuite/transko/one.stp b/testsuite/transko/one.stp
index 3c69161d..508ce9d4 100755
--- a/testsuite/transko/one.stp
+++ b/testsuite/transko/one.stp
@@ -1,6 +1,6 @@
#! stap -p3
probe begin {
- 1 = a
- a+1 = 4
+ print (1 = a)
+ print (a+1 = 4)
}
diff --git a/testsuite/transok/five.stp b/testsuite/transok/five.stp
index 1b132409..db19b31f 100755
--- a/testsuite/transok/five.stp
+++ b/testsuite/transok/five.stp
@@ -13,5 +13,7 @@ probe begin
for (a=0; a<=4; a=a+1) { b = a }
while (99) next
+ while (99) break
+ while (99) continue
while (99) {}
}
diff --git a/translate.cxx b/translate.cxx
index b6f83540..433cf23a 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -1863,10 +1863,10 @@ c_tmpcounter::visit_block (block *s)
void
c_tmpcounter::visit_for_loop (for_loop *s)
{
- s->init->visit (this);
+ if (s->init) s->init->visit (this);
s->cond->visit (this);
s->block->visit (this);
- s->incr->visit (this);
+ if (s->incr) s->incr->visit (this);
}
@@ -1881,7 +1881,7 @@ c_unparser::visit_for_loop (for_loop *s)
string breaklabel = "break_" + ctr;
// initialization
- s->init->visit (this);
+ if (s->init) s->init->visit (this);
// condition
o->newline(-1) << toplabel << ":";
@@ -1901,7 +1901,7 @@ c_unparser::visit_for_loop (for_loop *s)
// iteration
o->newline(-1) << contlabel << ":";
o->indent(1);
- s->incr->visit (this);
+ if (s->incr) s->incr->visit (this);
o->newline() << "goto " << toplabel << ";";
// exit
@@ -3644,10 +3644,15 @@ emit_symbol_data (systemtap_session& s)
if (rc == 0)
{
ifstream kallsyms (sorted_kallsyms.c_str());
+ char kallsyms_outbuf [4096];
+ ofstream kallsyms_out ((s.tmpdir + "/stap-symbols.h").c_str());
+ kallsyms_out.rdbuf()->pubsetbuf (kallsyms_outbuf,
+ sizeof(kallsyms_outbuf));
+
+ s.op->newline() << "\n\n#include \"stap-symbols.h\"";
unsigned i=0;
- s.op->newline() << "struct stap_symbol stap_symbols [] = {";
- s.op->indent(1);
+ kallsyms_out << "struct stap_symbol stap_symbols [] = {";
string lastaddr;
while (! kallsyms.eof())
{
@@ -3664,15 +3669,16 @@ emit_symbol_data (systemtap_session& s)
// NB: kallsyms includes some duplicate addresses
if ((type == "t" || type == "T") && lastaddr != addr)
{
- s.op->newline() << "{ 0x" << addr << ", "
- << "\"" << sym << "\", "
- << "\"" << module << "\" },";
+ kallsyms_out << " { 0x" << addr << ", "
+ << "\"" << sym << "\", "
+ << "\"" << module << "\" },"
+ << "\n";
lastaddr = addr;
i ++;
}
}
- s.op->newline(-1) << "};";
- s.op->newline() << "unsigned stap_num_symbols = " << i << ";\n";
+ kallsyms_out << "};\n";
+ kallsyms_out << "unsigned stap_num_symbols = " << i << ";\n";
}
return rc;
@@ -3691,7 +3697,9 @@ translate_pass (systemtap_session& s)
try
{
// This is at the very top of the file.
- s.op->line() << "#define TEST_MODE " << (s.test_mode ? 1 : 0) << "\n";
+
+ // XXX: the runtime uses #ifdef TEST_MODE to infer systemtap usage.
+ s.op->line() << "#define TEST_MODE 0\n";
s.op->newline() << "#ifndef MAXNESTING";
s.op->newline() << "#define MAXNESTING 10";
@@ -3725,9 +3733,6 @@ translate_pass (systemtap_session& s)
if (s.bulk_mode)
s.op->newline() << "#define STP_RELAYFS";
- s.op->newline() << "#if TEST_MODE";
- s.op->newline() << "#include \"runtime.h\"";
- s.op->newline() << "#else";
s.op->newline() << "#include \"runtime.h\"";
s.op->newline() << "#include \"current.c\"";
s.op->newline() << "#include \"stack.c\"";
@@ -3736,7 +3741,6 @@ translate_pass (systemtap_session& s)
s.op->newline() << "#include <linux/timer.h>";
s.op->newline() << "#include <linux/delay.h>";
s.op->newline() << "#include <linux/profile.h>";
- s.op->newline() << "#endif";
s.op->newline() << "#include \"loc2c-runtime.h\" ";
s.up->emit_common_header ();
@@ -3776,18 +3780,7 @@ translate_pass (systemtap_session& s)
s.up->emit_module_exit ();
s.op->newline();
- s.op->newline() << "#if TEST_MODE";
- s.op->newline() << "/* test mode mainline */";
- s.op->newline() << "int main () {";
- s.op->newline(1) << "int rc = systemtap_module_init ();";
- s.op->newline() << "if (!rc) systemtap_module_exit ();";
- s.op->newline() << "return rc;";
- s.op->newline(-1) << "}";
-
- s.op->newline() << "#else";
-
- s.op->newline();
// XXX impedance mismatch
s.op->newline() << "int probe_start () {";
s.op->newline(1) << "return systemtap_module_init () ? -1 : 0;";
@@ -3799,7 +3792,6 @@ translate_pass (systemtap_session& s)
s.op->newline() << "MODULE_DESCRIPTION(\"systemtap probe\");";
s.op->newline() << "MODULE_LICENSE(\"GPL\");"; // XXX
- s.op->newline() << "#endif";
}
catch (const semantic_error& e)
{