summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--ChangeLog14
-rw-r--r--Makefile.am3
-rw-r--r--Makefile.in7
-rw-r--r--buildrun.cxx50
-rw-r--r--buildrun.h18
-rw-r--r--elaborate.cxx6
-rw-r--r--elaborate.h19
-rw-r--r--main.cxx267
-rw-r--r--parse.cxx2
-rw-r--r--staptree.h4
-rw-r--r--tapsets.cxx10
-rw-r--r--translate.cxx85
13 files changed, 392 insertions, 95 deletions
diff --git a/AUTHORS b/AUTHORS
index 79407cb7..2310e573 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1 +1,3 @@
Frank Ch. Eigler <fche@redhat.com>
+Graydon Hoare <graydon@redhat.com>
+
diff --git a/ChangeLog b/ChangeLog
index d16109be..916ac1e8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2005-07-05 Frank Ch. Eigler <fche@redhat.com>
+
+ * elaborate.h (systemtap_session): Add more command-line arguments.
+ * staptree.h (verbose): Bad global, no donut.
+ * elaborate.cxx: Temporarily disable verbose variable access.
+ * main.cxx: Support more arguments, build/run passes. Revamp
+ temporary file generation and partial-pass output generation.
+ * tapsets.cxx, translate.cxx: Emit just enough extra punctuation
+ and fluff to make generated probe pass -Werror.
+ * buildrun.cxx, buildrun.h: New files for passes 4/5. Partial
+ support for build pass, nothing on probe execution yet.
+ * testsuite/transok/*.stp: Force just -p3, now that -p4/5 exist.
+ * Makefile.am, Makefile.in: Corresponding changes.
+
2005-07-04 Graydon Hoare <graydon@redhat.com>
* elaborate.h (symresolution_info::current_derived_probe): New field.
diff --git a/Makefile.am b/Makefile.am
index 40bcd440..f56f71a0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,7 +6,8 @@ AM_MAKEFLAGS = 'CXXFLAGS=$(CXXFLAGS)' 'LDFLAGS=$(LDFLAGS)'
bin_PROGRAMS =
noinst_PROGRAMS = stap
stap_SOURCES = main.cxx \
- parse.cxx staptree.cxx elaborate.cxx translate.cxx tapsets.cxx
+ parse.cxx staptree.cxx elaborate.cxx translate.cxx \
+ tapsets.cxx buildrun.cxx
AM_CXXFLAGS = -Wall
# Get extra libs as needed
diff --git a/Makefile.in b/Makefile.in
index 479563d5..26edb195 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -58,7 +58,8 @@ am__installdirs = "$(DESTDIR)$(bindir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
am_stap_OBJECTS = main.$(OBJEXT) parse.$(OBJEXT) staptree.$(OBJEXT) \
- elaborate.$(OBJEXT) translate.$(OBJEXT) tapsets.$(OBJEXT)
+ elaborate.$(OBJEXT) translate.$(OBJEXT) tapsets.$(OBJEXT) \
+ buildrun.$(OBJEXT)
stap_OBJECTS = $(am_stap_OBJECTS)
stap_LDADD = $(LDADD)
stap_DEPENDENCIES =
@@ -175,7 +176,8 @@ sysconfdir = @sysconfdir@
target_alias = @target_alias@
AM_MAKEFLAGS = 'CXXFLAGS=$(CXXFLAGS)' 'LDFLAGS=$(LDFLAGS)'
stap_SOURCES = main.cxx \
- parse.cxx staptree.cxx elaborate.cxx translate.cxx tapsets.cxx
+ parse.cxx staptree.cxx elaborate.cxx translate.cxx \
+ tapsets.cxx buildrun.cxx
AM_CXXFLAGS = -Wall
@@ -288,6 +290,7 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buildrun.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elaborate.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@
diff --git a/buildrun.cxx b/buildrun.cxx
new file mode 100644
index 00000000..af22f1c8
--- /dev/null
+++ b/buildrun.cxx
@@ -0,0 +1,50 @@
+// build/run probes
+// Copyright (C) 2005 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 "config.h"
+#include "buildrun.h"
+
+#include <fstream>
+
+using namespace std;
+
+
+int
+compile_pass (systemtap_session& s)
+{
+ // fill in a quick Makefile
+ if (1)
+ {
+ // Assumes linux 2.6 kbuild
+ string makefile_nm = s.tmpdir + "/Makefile";
+ ofstream o (makefile_nm.c_str());
+ o << "CFLAGS += -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;
+ }
+
+ // run module make
+ string module_dir = string("/lib/modules/") + s.kernel_release + "/build";
+ string make_cmd = string("make")
+ + string (" -C \"") + module_dir + string("\"");
+ if (! s.verbose) make_cmd += " -s";
+ make_cmd += string(" M=\"") + s.tmpdir + string("\" modules");
+
+ if (s.verbose) cerr << "Running " << make_cmd << endl;
+ int rc = system (make_cmd.c_str());
+ if (s.verbose) cerr << "rc=" << rc << endl;
+ return rc;
+}
+
+
+int
+run_pass (systemtap_session& s)
+{
+ return 1;
+}
diff --git a/buildrun.h b/buildrun.h
new file mode 100644
index 00000000..88a63a5e
--- /dev/null
+++ b/buildrun.h
@@ -0,0 +1,18 @@
+// -*- C++ -*-
+// Copyright (C) 2005 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 BUILDRUN_H
+#define BUILDRUN_H
+
+#include "elaborate.h"
+
+int compile_pass (systemtap_session& s);
+int run_pass (systemtap_session& s);
+
+
+#endif // BUILDRUN_H
diff --git a/elaborate.cxx b/elaborate.cxx
index b6a64164..890d6f4a 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -174,18 +174,18 @@ match_node::find_builder(vector<probe_point::component *> const & components,
// an entry in the sub table, and its value matches the rest
// of the probe_point.
match_key k(*components[pos]);
- if (verbose)
+ if (0) // session.verbose
clog << "searching for component " << k.str() << endl;
map<match_key, match_node *>::const_iterator i = sub.find(k);
if (i == sub.end())
{
- if (verbose)
+ if (0) // session.verbose
clog << "no match found" << endl;
return NULL;
}
else
{
- if (verbose)
+ if (0) // session.verbose
clog << "matched " << k.str() << endl;
derived_probe_builder * builder = NULL;
if (k.have_parameter)
diff --git a/elaborate.h b/elaborate.h
index 5855c92d..e61796fa 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -195,6 +195,22 @@ struct systemtap_session
{
systemtap_session ();
+ // command line args
+ std::vector<std::string> include_path;
+ std::vector<std::string> args;
+ std::string kernel_release;
+ std::string runtime_path;
+ std::string module_name;
+ int last_pass;
+ bool test_mode;
+ bool verbose;
+ bool keep_tmpdir;
+
+ // temporary directory for module builds etc.
+ // hazardous - it is "rm -rf"'d at exit
+ std::string tmpdir;
+ std::string translated_source; // C source code
+
match_node * pattern_root;
void register_library_aliases();
@@ -202,9 +218,6 @@ struct systemtap_session
stapfile* user_file;
std::vector<stapfile*> library_files;
- // configuration options
- // bool verbose_resolution;
-
// resolved globals/functions/probes for the run as a whole
std::vector<stapfile*> files;
std::vector<vardecl*> globals;
diff --git a/main.cxx b/main.cxx
index a31d53fa..ca2f4dd3 100644
--- a/main.cxx
+++ b/main.cxx
@@ -1,4 +1,4 @@
-// systemtap translator driver
+// systemtap translator/driver
// Copyright (C) 2005 Red Hat Inc.
//
// This file is part of systemtap, and is free software. You can
@@ -11,38 +11,67 @@
#include "parse.h"
#include "elaborate.h"
#include "translate.h"
+#include "buildrun.h"
#include <iostream>
#include <fstream>
#include <sstream>
+#include <cerrno>
extern "C" {
#include <glob.h>
#include <unistd.h>
+#include <sys/utsname.h>
+#include <time.h>
}
using namespace std;
-bool verbose = false;
-void usage ()
+void
+usage (systemtap_session& s)
{
- cerr << "SystemTap translator "
- << "(version " << VERSION << " built " << DATE << ")" << endl;
- cerr << "Copyright (C) 2005 Red Hat, Inc." << endl;
- cerr << "This is free software; see the source for copying conditions." << endl;
- cerr << endl;
- cerr << "Usage: stap [options] FILE [ARGS ...] Run script in file." << endl;
- cerr << " or: stap [options] - [ARGS ...] Run script on stdin." << endl;
- cerr << " or: stap [options] -e SCRIPT [ARGS ...] Run given script." << endl;
- cerr << endl;
- cerr << "Arguments:" << endl;
- cerr << " -- No more options after this" << endl;
- cerr << " -v verbose" << endl;
- cerr << " -p NUM Stop after pass NUM 1-3" << endl;
- cerr << " (parse, elaborate, translate)" << endl;
- cerr << " -I DIR Look in DIR for additional .stp script files." << endl;
- cerr << " -o FILE Send output to file instead of stdout." << endl;
+ cerr
+ << "SystemTap translator "
+ << "(version " << VERSION << " built " << DATE << ")" << endl
+ << "Copyright (C) 2005 Red Hat, Inc." << endl
+ << "This is free software; see the source for copying conditions."
+ << endl
+ << endl
+ << "Usage: stap [options] FILE [ARGS ...] Run script in file."
+ << endl
+ << " or: stap [options] - [ARGS ...] Run script on stdin."
+ << endl
+ << " or: stap [options] -e SCRIPT [ARGS ...] Run given script."
+ << endl
+ << endl
+ << "Arguments:" << endl
+ << " -- no more options after this" << endl
+ << " -v verbose" << (s.verbose ? " [set]" : "")
+ << endl
+ << " -t test mode" << (s.test_mode ? " [set]" : "")
+ << endl
+ << " -p NUM stop after pass NUM 1-5" << endl
+ << " (parse, elaborate, translate, compile, run)" << endl
+ << " -I DIR look in DIR for additional .stp script files";
+ if (s.include_path.size() == 0)
+ cerr << endl;
+ else
+ cerr << ", instead of" << endl;
+ for (unsigned i=0; i<s.include_path.size(); i++)
+ cerr << " " << s.include_path[i] << endl;
+ cerr
+ << " -R DIR look in DIR for runtime, instead of "
+ << s.runtime_path
+ << endl
+ << " -r RELEASE use kernel RELEASE, instead of "
+ << s.kernel_release
+ << endl
+ << " -m MODULE set probe module name, insetad of "
+ << s.module_name
+ << endl
+ << " -o FILE send output to file instead of stdout" << endl
+ << " -k keep temporary directory" << endl;
// XXX: other options:
// -s: safe mode
// -d: dump safety-related external references
@@ -51,57 +80,97 @@ void usage ()
}
+// little utility function
+
+template <typename T>
+static string
+stringify(T t)
+{
+ ostringstream s;
+ s << t;
+ return s.str ();
+}
+
+
int
main (int argc, char * const argv [])
{
- int last_pass = 3; // -p NUM
string cmdline_script; // -e PROGRAM
string script_file; // FILE
bool have_script = false;
- string output_file; // -o FILE
- vector<string> include_path; // -I DIR
- vector<string> args; // ARGS
+ string output_file = "-"; // -o FILE
+
+ // Initialize defaults
+ systemtap_session s;
+ struct utsname buf;
+ (void) uname (& buf);
+ s.kernel_release = string (buf.release);
+ s.verbose = false;
+ s.test_mode = false;
+ s.last_pass = 5;
+ s.runtime_path = "/usr/share/systemtap/runtime"; // XXX
+ s.module_name = "stap_" + stringify(getuid()) + "_" + stringify(time(0));
+ s.keep_tmpdir = false;
+
while (true)
{
- int grc = getopt (argc, argv, "vp:I:e:o:");
+ int grc = getopt (argc, argv, "vp:I:e:o:tR:r:m:k");
if (grc < 0)
break;
switch (grc)
{
case 'v':
- verbose = true;
+ s.verbose = true;
break;
case 'p':
- last_pass = atoi (optarg);
- if (last_pass < 1 || last_pass > 3)
+ s.last_pass = atoi (optarg);
+ if (s.last_pass < 1 || s.last_pass > 5)
{
cerr << "Invalid pass number." << endl;
- usage ();
+ usage (s);
}
break;
case 'I':
- include_path.push_back (string (optarg));
+ s.include_path.push_back (string (optarg));
break;
case 'e':
if (have_script)
- usage ();
+ usage (s);
cmdline_script = string (optarg);
have_script = true;
break;
case 'o':
- if (output_file != "")
- usage ();
output_file = string (optarg);
break;
+ case 't':
+ s.test_mode = true;
+ break;
+
+ case 'R':
+ s.runtime_path = string (optarg);
+ break;
+
+ case 'm':
+ s.module_name = string (optarg);
+ break;
+
+ case 'r':
+ s.kernel_release = string (optarg);
+ break;
+
+ case 'k':
+ s.keep_tmpdir = true;
+ break;
+
case '?':
case 'h':
default:
- usage ();
+ usage (s);
}
}
@@ -113,21 +182,32 @@ main (int argc, char * const argv [])
have_script = true;
}
else
- args.push_back (string (argv[i]));
+ s.args.push_back (string (argv[i]));
}
// need a user file
if (! have_script)
- usage();
+ usage(s);
+
+ int rc = 0;
// arguments parsed; get down to business
- int rc = 0;
- systemtap_session s;
- if (output_file != "")
- s.op = new translator_output (output_file);
- else
- s.op = new translator_output (cout);
+ // Create a temporary directory to build within.
+ // Be careful with this, as "s.tmpdir" is "rm -rf"'d at the end.
+ {
+ char tmpdirt[] = "/tmp/stapXXXXXX";
+ const char* tmpdir = mkdtemp (tmpdirt);
+ if (! tmpdir)
+ {
+ const char* e = strerror (errno);
+ cerr << "mkdtemp (\"" << tmpdir << "\"): " << e << endl;
+ s.tmpdir = "";
+ rc = 1;
+ }
+ else
+ s.tmpdir = tmpdir;
+ }
// PASS 1a: PARSING USER SCRIPT
@@ -147,10 +227,10 @@ main (int argc, char * const argv [])
rc ++;
// PASS 1b: PARSING LIBRARY SCRIPTS
- for (unsigned i=0; i<include_path.size(); i++)
+ for (unsigned i=0; i<s.include_path.size(); i++)
{
glob_t globbuf;
- string dir = include_path[i] + "/*.stp";
+ string dir = s.include_path[i] + "/*.stp";
int r = glob(dir.c_str (), 0, NULL, & globbuf);
if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
rc ++;
@@ -168,70 +248,119 @@ main (int argc, char * const argv [])
globfree (& globbuf);
}
- if (last_pass == 1 && rc == 0)
+ if (rc == 0 && s.last_pass == 1)
{
- s.op->line() << "# parse tree dump";
- s.user_file->print (s.op->newline());
+ cout << "# parse tree dump" << endl;
+ s.user_file->print (cout);
+ cout << endl;
for (unsigned i=0; i<s.library_files.size(); i++)
- s.library_files[i]->print (s.op->newline());
+ {
+ s.library_files[i]->print (cout);
+ cout << endl;
+ }
}
+
// PASS 2: ELABORATION
- if (rc == 0 && last_pass > 1)
+ if (rc == 0 && s.last_pass > 1)
rc = semantic_pass (s);
- if (last_pass == 2 && rc == 0)
+
+ if (rc == 0 && s.last_pass == 2)
{
if (s.globals.size() > 0)
- s.op->line() << "# globals";
+ cout << "# globals" << endl;
for (unsigned i=0; i<s.globals.size(); i++)
{
vardecl* v = s.globals[i];
- v->printsig (s.op->newline());
+ v->printsig (cout);
+ cout << endl;
}
if (s.functions.size() > 0)
- s.op->newline() << "# functions";
+ cout << "# functions" << endl;
for (unsigned i=0; i<s.functions.size(); i++)
{
functiondecl* f = s.functions[i];
- f->printsig (s.op->newline());
- s.op->indent(1);
+ f->printsig (cout);
+ cout << endl;
if (f->locals.size() > 0)
- s.op->newline(1) << "# locals";
+ cout << " # locals" << endl;
for (unsigned j=0; j<f->locals.size(); j++)
{
vardecl* v = f->locals[j];
- v->printsig (s.op->newline());
+ cout << " ";
+ v->printsig (cout);
+ cout << endl;
}
- s.op->indent(-1);
}
if (s.probes.size() > 0)
- s.op->newline() << "# probes";
+ cout << "# probes" << endl;
for (unsigned i=0; i<s.probes.size(); i++)
{
derived_probe* p = s.probes[i];
- p->printsig (s.op->newline());
- s.op->indent(1);
+ p->printsig (cout);
+ cout << endl;
if (p->locals.size() > 0)
- s.op->newline() << "# locals";
+ cout << " # locals" << endl;
for (unsigned j=0; j<p->locals.size(); j++)
{
vardecl* v = p->locals[j];
- v->printsig (s.op->newline());
+ cout << " ";
+ v->printsig (cout);
+ cout << endl;
}
- s.op->indent(-1);
}
-
- s.op->newline();
}
+
// PASS 3: TRANSLATION
- if (rc == 0 && last_pass > 2)
- rc = translate_pass (s);
+ if (rc == 0 && s.last_pass > 2)
+ {
+ s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c";
+ rc = translate_pass (s);
+ }
+
+ if (rc == 0 && s.last_pass == 3)
+ {
+ ifstream i (s.translated_source.c_str());
+ cout << i.rdbuf();
+ }
+
+ // PASS 4: COMPILATION
+ if (rc == 0 && s.last_pass > 3)
+ {
+ rc = compile_pass (s);
+ }
+
+ // PASS 5: RUN
+ if (rc == 0 && s.last_pass > 4)
+ {
+ rc = run_pass (s);
+ }
+
+ // Pull out saved output
+ if (output_file != "-")
+ s.op = new translator_output (output_file);
+ else
+ s.op = new translator_output (cout);
+
- s.op->line() << endl;
- delete s.op;
+ // Clean up temporary directory. Obviously, be careful with this.
+ if (s.tmpdir == "")
+ ; // do nothing
+ else
+ {
+ if (s.keep_tmpdir)
+ cerr << "Keeping temporary directory \"" << s.tmpdir << "\"" << endl;
+ else
+ {
+ string cleanupcmd = "/bin/rm -rf ";
+ cleanupcmd += s.tmpdir;
+ if (s.verbose) cerr << "Running " << cleanupcmd << endl;
+ (void) system (cleanupcmd.c_str());
+ }
+ }
return rc;
}
diff --git a/parse.cxx b/parse.cxx
index d8953f68..bcf634e6 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -668,7 +668,7 @@ parser::parse_probe_point ()
probe_point* pl = new probe_point;
// XXX: add support for probe point aliases
- // e.g. probe a.b = a.c = a.d = foo
+ // e.g. probe alias = foo { ... }
while (1)
{
const token* t = next ();
diff --git a/staptree.h b/staptree.h
index 8d55f053..858c93a0 100644
--- a/staptree.h
+++ b/staptree.h
@@ -14,7 +14,6 @@
#include <iostream>
#include <stdexcept>
-extern bool verbose;
struct token; // parse.h
struct semantic_error: public std::runtime_error
@@ -377,7 +376,6 @@ struct probe_point
component ();
};
std::vector<component*> components;
- // XXX: probe aliases
const token* tok; // points to first component's functor
void print (std::ostream& o);
probe_point ();
@@ -408,7 +406,7 @@ struct probe_alias
};
-// An derived visitor instance is used to visit the entire
+// A derived visitor instance is used to visit the entire
// statement/expression tree.
struct visitor
{
diff --git a/tapsets.cxx b/tapsets.cxx
index a56fb659..160cb2fe 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -70,7 +70,7 @@ be_derived_probe::emit_registrations (translator_output* o, unsigned j)
if (begin)
for (unsigned i=0; i<locations.size(); i++)
{
- o->newline() << "enter_" << j << "_" << i << " ()";
+ o->newline() << "enter_" << j << "_" << i << " ();";
o->newline() << "rc = errorcount;";
}
else
@@ -86,7 +86,7 @@ be_derived_probe::emit_deregistrations (translator_output* o, unsigned j)
else
for (unsigned i=0; i<locations.size(); i++)
{
- o->newline() << "enter_" << j << "_" << i << " ()";
+ o->newline() << "enter_" << j << "_" << i << " ();";
o->newline() << "rc = errorcount;";
}
}
@@ -99,8 +99,8 @@ be_derived_probe::emit_probe_entries (translator_output* o, unsigned j)
{
probe_point *l = locations[i];
o->newline() << "/* location " << i << ": " << *l << " */";
- o->newline() << "static void enter_" << j << "_" << i << " ()";
- o->newline() << "{";
+ o->newline() << "static void enter_" << j << "_" << i << " (void);";
+ o->newline() << "void enter_" << j << "_" << i << " () {";
o->newline(1) << "struct context* c = & contexts [0];";
// XXX: assert #0 is free; need locked search instead
o->newline() << "if (c->busy) { errorcount ++; return; }";
@@ -1063,6 +1063,8 @@ dwarf_derived_probe::emit_probe_entries (translator_output* o, unsigned probenum
o->newline();
o->newline() << "static void ";
+ o->newline() << probe_entry_function_name(probenum) << " (void);";
+ o->newline() << "void ";
o->newline() << probe_entry_function_name(probenum) << " ()";
o->newline() << "{";
o->newline(1) << "struct context* c = & contexts [0];";
diff --git a/translate.cxx b/translate.cxx
index 7336d172..cb25044b 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -177,7 +177,13 @@ struct c_tmpcounter: public traversing_visitor
void
c_unparser::emit_common_header ()
{
- o->newline() << "#include <string.h>";
+ o->newline() << "#if TEST_MODE";
+ o->newline() << "#include <string.h>";
+ o->newline() << "#else";
+ o->newline() << "#include <linux/string.h>";
+ // XXX: tapsets.cxx should be able to add additional definitions
+ o->newline() << "#endif";
+
o->newline() << "#define NR_CPU 1";
o->newline() << "#define MAXNESTING 30";
o->newline() << "#define MAXCONCURRENCY NR_CPU";
@@ -273,10 +279,14 @@ c_unparser::emit_functionsig (functiondecl* v)
void
c_unparser::emit_module_init ()
{
- o->newline() << "int STARTUP () {";
+ o->newline() << "static int systemtap_module_init (void);";
+ o->newline() << "int systemtap_module_init () {";
o->newline(1) << "int anyrc = 0;";
o->newline() << "int rc;";
+ // XXX: yuck runtime
+ o->newline() << "TRANSPORT_OPEN;";
+
for (unsigned i=0; i<session->globals.size(); i++)
{
vardecl* v = session->globals[i];
@@ -315,7 +325,15 @@ c_unparser::emit_module_init ()
void
c_unparser::emit_module_exit ()
{
- o->newline() << "int SHUTDOWN () {";
+ // XXX: double-yuck runtime
+ o->newline() << "void probe_exit () {";
+ // need to reference these static functions for -Werror avoidance
+ o->newline(1) << "if (0) next_fmt ((void *) 0, (void *) 0);";
+ o->newline() << "if (0) _stp_dbug(\"\", 0, \"\");";
+ o->newline(-1) << "}";
+ //
+ o->newline() << "static void systemtap_module_exit (void);";
+ o->newline() << "void systemtap_module_exit () {";
o->newline(1) << "int anyrc = 0;";
o->newline() << "int rc;";
for (unsigned i=0; i<session->probes.size(); i++)
@@ -324,7 +342,8 @@ c_unparser::emit_module_exit ()
o->newline() << "anyrc |= rc;";
}
// XXX: uninitialize globals
- o->newline() << "return anyrc; /* if (anyrc) log badness */";
+ o->newline() << "_stp_transport_close ();";
+ // XXX: if anyrc, log badness
o->newline(-1) << "}" << endl;
}
@@ -332,7 +351,7 @@ c_unparser::emit_module_exit ()
void
c_unparser::emit_function (functiondecl* v)
{
- o->newline() << "static void function_" << c_varname (v->name)
+ o->newline() << "void function_" << c_varname (v->name)
<< " (struct context* c) {";
o->indent(1);
this->current_probe = 0;
@@ -383,7 +402,8 @@ c_unparser::emit_function (functiondecl* v)
void
c_unparser::emit_probe (derived_probe* v, unsigned i)
{
- o->newline() << "static void probe_" << i << " (struct context *c) {";
+ o->newline() << "static void probe_" << i << " (struct context *c);";
+ o->newline() << "void probe_" << i << " (struct context *c) {";
o->indent(1);
// initialize frame pointer
@@ -1419,36 +1439,83 @@ translate_pass (systemtap_session& s)
{
int rc = 0;
+ s.op = new translator_output (s.translated_source);
c_unparser cup (& s);
s.up = & cup;
try
{
- s.op->newline() << "/* common header */";
+ s.op->line() << "#define TEST_MODE " << (s.test_mode ? 1 : 0)
+ << endl;
+
+ // XXX: until the runtime can handle user-level tests properly
+ s.op->newline() << "#if ! TEST_MODE";
+ s.op->newline() << "#define STP_NETLINK_ONLY"; // XXX
+ s.op->newline() << "#include \"runtime.h\"";
+ s.op->newline() << "#endif" << endl;
+
s.up->emit_common_header ();
+
s.op->newline() << "/* globals */";
for (unsigned i=0; i<s.globals.size(); i++)
s.up->emit_global (s.globals[i]);
+
s.op->newline() << "/* function signatures */";
for (unsigned i=0; i<s.functions.size(); i++)
s.up->emit_functionsig (s.functions[i]);
+
s.op->newline() << "/* functions */";
for (unsigned i=0; i<s.functions.size(); i++)
s.up->emit_function (s.functions[i]);
+
s.op->newline() << "/* probes */";
for (unsigned i=0; i<s.probes.size(); i++)
s.up->emit_probe (s.probes[i], i);
- s.op->newline() << "/* module init */";
+
s.up->emit_module_init ();
- s.op->newline() << "/* module exit */";
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) rc = systemtap_module_exit ();";
+ s.op->newline() << "return rc;";
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "#else";
+
s.op->newline();
+ s.op->newline() << "static int __init _systemtap_module_init (void);";
+ s.op->newline() << "int _systemtap_module_init () {";
+ s.op->newline(1) << "return systemtap_module_init ();";
+ s.op->newline(-1) << "}";
+
+ s.op->newline();
+ s.op->newline() << "static void __exit _systemtap_module_exit (void);";
+ s.op->newline() << "void _systemtap_module_exit () {";
+ s.op->newline(1) << "systemtap_module_exit ();";
+ s.op->newline(-1) << "}";
+
+ s.op->newline();
+ s.op->newline() << "module_init (_systemtap_module_init);";
+ s.op->newline() << "module_exit (_systemtap_module_exit);";
+ s.op->newline() << "MODULE_DESCRIPTION(\"systemtap probe\");";
+ s.op->newline() << "MODULE_LICENSE(\"GPL\");"; // XXX
+
+ s.op->newline() << "#endif";
+
+ s.op->line() << endl;
}
catch (const semantic_error& e)
{
s.print_error (e);
}
+ delete s.op;
+ s.op = 0;
s.up = 0;
return rc + s.num_errors;
}