summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--Makefile.am2
-rw-r--r--Makefile.in3
-rw-r--r--TODO27
-rw-r--r--parse.cxx95
-rw-r--r--parse.h2
-rw-r--r--parsetest.cxx4
-rwxr-xr-xruntest.sh5
-rw-r--r--semtest.cxx65
-rw-r--r--staptree.cxx31
-rw-r--r--staptree.h20
-rwxr-xr-xtestsuite/parseko/five.stp16
-rwxr-xr-xtestsuite/parseko/six.stp8
-rwxr-xr-xtestsuite/parseok/five.stp19
-rwxr-xr-xtestsuite/parseok/four.stp7
-rwxr-xr-xtestsuite/parseok/six.stp8
-rwxr-xr-xtestsuite/parseok/three.stp2
-rwxr-xr-xtestsuite/parseok/two.stp4
-rwxr-xr-xtestsuite/semko/one.stp2
-rwxr-xr-xtestsuite/semok/four.stp2
-rwxr-xr-xtestsuite/semok/one.stp2
21 files changed, 255 insertions, 83 deletions
diff --git a/ChangeLog b/ChangeLog
index d87b69dd..6a5c3dc4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2005-03-15 Frank Ch. Eigler <fche@redhat.com>
+
+ * TODO: New file. Include some probe-point-provider syntax examples.
+ * parse.cxx (lexer::scan, parser::parse_literal): Support hex, octal
+ numbers via strtol.
+ (parse_probe, parse_probe_point): Modify for dotted syntax.
+ * staptree.cxx: Ditto.
+ * parsetest.cxx, semtest.cxx: Print parse/sem results even if
+ .stp files were given on command line.
+ * parse.h, staptree.h: Rename probe_point_spec -> probe_point.
+ * runtest.sh: New test-runner front-end script.
+ * Makefile.am: Use it for TESTS_ENVIRONMENT.
+ * testsuite/*: Update probe point syntax. Add a bunch of new tests.
+
2005-03-04 Frank Ch. Eigler <fche@redhat.com>
* parse.cxx (scan): Support '$' characters in identifiers.
diff --git a/Makefile.am b/Makefile.am
index 1ba8071a..ff1651c4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,3 +25,5 @@ s=$(srcdir)/testsuite/sem
TESTS = $(wildcard $(p)ok/*.stp) $(wildcard $(p)ko/*.stp) \
$(wildcard $(s)ok/*.stp) $(wildcard $(s)ko/*.stp)
XFAIL_TESTS = $(wildcard $(p)ko/*.stp) $(wildcard $(s)ko/*.stp)
+
+TESTS_ENVIRONMENT = $(srcdir)/runtest.sh
diff --git a/Makefile.in b/Makefile.in
index c93c7757..2b995761 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -44,7 +44,7 @@ subdir = .
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/config.in \
$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
- depcomp install-sh missing
+ TODO depcomp install-sh missing
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
@@ -193,6 +193,7 @@ TESTS = $(wildcard $(p)ok/*.stp) $(wildcard $(p)ko/*.stp) \
$(wildcard $(s)ok/*.stp) $(wildcard $(s)ko/*.stp)
XFAIL_TESTS = $(wildcard $(p)ko/*.stp) $(wildcard $(s)ko/*.stp)
+TESTS_ENVIRONMENT = $(srcdir)/runtest.sh
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
diff --git a/TODO b/TODO
new file mode 100644
index 00000000..31729089
--- /dev/null
+++ b/TODO
@@ -0,0 +1,27 @@
+LANGUAGE
+ - lock (var) { block }
+ - /* */ and // comments
+
+PROVIDERS
+ lkst("process_contextswitch")
+ syscall("name").return
+ syscall("*")
+ kernel.function("wait_for_godot")
+ kernel.function("name").line(10)
+ kernel.source("mempool.c").line(5004)
+ kernel.address(0xdeadbeef)
+ kernel.module("driver.ko").function("name").return
+ kernel.module("cpqarray.ko").jumptable("ida_fops")
+ kernel.watch("datasymbol").write
+ user("fche").inode("/bin/vi").function("refresh")
+ user.inode("/lib/libc.so.6").function("malloc").return
+ time.real.hz(500)
+ time.virtual.jiffies(100)
+ perfcounter("tlbmiss").count(4000)
+ resource.freemembelow(50) # pages?
+ begin
+ end
+
+KPROBES
+ - smp friendliness: no kprobes-wide lock held during probe execution
+
diff --git a/parse.cxx b/parse.cxx
index 640c3715..91600e25 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -6,7 +6,10 @@
#include "staptree.h"
#include "parse.h"
#include <cctype>
+#include <cstdlib>
#include <fstream>
+#include <cerrno>
+#include <climits>
using namespace std;
@@ -179,17 +182,22 @@ lexer::scan ()
else if (isdigit (c))
{
- // XXX: support 0xHEX etc.
n->type = tok_number;
- n->content = c;
+ n->content = (char) c;
+
while (1)
{
int c2 = input.peek ();
if (! input)
break;
- if (isdigit(c2))
+
+ // NB: isalnum is very permissive. We rely on strtol, called in
+ // parser::parse_literal below, to confirm that the number string
+ // is correctly formatted and in range.
+
+ if (isalnum (c2))
{
- n->content.push_back(c2);
+ n->content.push_back (c2);
input_get ();
}
else
@@ -344,10 +352,10 @@ parser::parse_probe ()
if (t && t->type == tok_identifier)
{
p->tok = t;
- p->location.push_back (parse_probe_point_spec ());
+ p->locations.push_back (parse_probe_point ());
t = peek ();
- if (t && t->type == tok_operator && t->content == ":")
+ if (t && t->type == tok_operator && t->content == ",")
{
next ();
continue;
@@ -355,11 +363,11 @@ parser::parse_probe ()
else if (t && t->type == tok_operator && t->content == "{")
break;
else
- throw parse_error ("expected ':' or '{'");
+ throw parse_error ("expected ',' or '{'");
// XXX: unify logic with that in parse_symbol()
}
else
- throw parse_error ("expected probe location specifier");
+ throw parse_error ("expected probe point specifier");
}
p->body = parse_stmt_block ();
@@ -524,25 +532,49 @@ parser::parse_functiondecl ()
}
-probe_point_spec*
-parser::parse_probe_point_spec ()
+probe_point*
+parser::parse_probe_point ()
{
- probe_point_spec* pl = new probe_point_spec;
+ probe_point* pl = new probe_point;
- const token* t = next ();
- if (t->type != tok_identifier)
- throw parse_error ("expected identifier");
- pl->functor = t->content;
- pl->tok = t;
-
- t = peek ();
- if (t && t->type == tok_operator && t->content == "(")
+ while (1)
{
- next (); // consume "("
- pl->arg = parse_literal ();
- const token* tt = next ();
- if (! (tt->type == tok_operator && tt->content == ")"))
- throw parse_error ("expected ')'");
+ const token* t = next ();
+ if (t->type != tok_identifier)
+ throw parse_error ("expected identifier");
+
+ if (pl->tok == 0) pl->tok = t;
+
+ probe_point::component* c = new probe_point::component;
+ c->functor = t->content;
+ pl->components.push_back (c);
+ // NB though we still may add c->arg soon
+
+ t = peek ();
+ if (t && t->type == tok_operator
+ && (t->content == "{" || t->content == ","))
+ break;
+
+ if (t && t->type == tok_operator && t->content == "(")
+ {
+ next (); // consume "("
+ c->arg = parse_literal ();
+
+ t = next ();
+ if (! (t->type == tok_operator && t->content == ")"))
+ throw parse_error ("expected ')'");
+
+ t = peek ();
+ if (t && t->type == tok_operator
+ && (t->content == "{" || t->content == ","))
+ break;
+ }
+ // fall through
+
+ if (t && t->type == tok_operator && t->content == ".")
+ next ();
+ else
+ throw parse_error ("expected '.'");
}
return pl;
@@ -557,7 +589,20 @@ parser::parse_literal ()
if (t->type == tok_string)
l = new literal_string (t->content);
else if (t->type == tok_number)
- l = new literal_number (atol (t->content.c_str ()));
+ {
+ const char* startp = t->content.c_str ();
+ char* endp = (char*) startp;
+
+ // NB: we allow controlled overflow from LONG_MIN .. ULONG_MAX
+ errno = 0;
+ long long value = strtoll (startp, & endp, 0);
+ if (errno == ERANGE || errno == EINVAL || *endp != '\0'
+ || value > ULONG_MAX || value < LONG_MIN)
+ throw parse_error ("number invalid or out of range");
+
+ long value2 = (long) value;
+ l = new literal_number (value2);
+ }
else
throw parse_error ("expected literal string or number");
diff --git a/parse.h b/parse.h
index c8008bc7..f2510d7e 100644
--- a/parse.h
+++ b/parse.h
@@ -82,7 +82,7 @@ private:
private: // nonterminals
probe* parse_probe ();
- probe_point_spec* parse_probe_point_spec ();
+ probe_point* parse_probe_point ();
literal* parse_literal ();
void parse_global (vector<vardecl*>&);
functiondecl* parse_functiondecl ();
diff --git a/parsetest.cxx b/parsetest.cxx
index ab1d53c8..6293a2f5 100644
--- a/parsetest.cxx
+++ b/parsetest.cxx
@@ -14,20 +14,18 @@ int main (int argc, char *argv [])
if (argc > 1)
{
- // quietly parse all listed input files
for (int i = 1; i < argc; i ++)
{
parser p (argv[i]);
stapfile* f = p.parse ();
if (f)
- cout << "file '" << argv[i] << "' parsed ok." << endl;
+ f->print (cout);
else
rc = 1;
}
}
else
{
- // parse then print just stdin
parser p (cin);
stapfile* f = p.parse ();
if (f)
diff --git a/runtest.sh b/runtest.sh
new file mode 100755
index 00000000..c67b66a8
--- /dev/null
+++ b/runtest.sh
@@ -0,0 +1,5 @@
+#! /bin/sh
+
+# Redirect stdout/stderr to /dev/null before invoking the given test
+
+exec $@ >/dev/null 2>&1
diff --git a/semtest.cxx b/semtest.cxx
index f86d17ca..b154209f 100644
--- a/semtest.cxx
+++ b/semtest.cxx
@@ -133,52 +133,49 @@ main (int argc, char *argv [])
rc += semantic_pass_1 (files);
rc += semantic_pass_2 (files);
- if (argc == 1) // processed stdin only
+ for (unsigned i=0; i<files.size(); i++)
{
- for (unsigned i=0; i<files.size(); i++)
+ stapfile* f = files[i];
+ for (unsigned j=0; j<f->functions.size(); j++)
{
- stapfile* f = files[i];
- for (unsigned j=0; j<f->functions.size(); j++)
- {
- functiondecl* fn = f->functions[j];
- cerr << "Function ";
- fn->printsig (cerr);
- cerr << endl << "locals:" << endl;
- for (unsigned k=0; k<fn->locals.size(); k++)
- {
- vardecl* fa = fn->locals[k];
- cerr << "\t";
- fa->printsig (cerr);
- cerr << endl;
- }
- cerr << endl;
- }
-
- for (unsigned j=0; j<f->probes.size(); j++)
+ functiondecl* fn = f->functions[j];
+ cerr << "Function ";
+ fn->printsig (cerr);
+ cerr << endl << "locals:" << endl;
+ for (unsigned k=0; k<fn->locals.size(); k++)
{
- probe* pn = f->probes[j];
- cerr << "Probe " << *pn->tok << endl; // XXX: print probespec
- cerr << "locals:" << endl;
- for (unsigned k=0; k<pn->locals.size(); k++)
- {
- vardecl* fa = pn->locals[k];
- cerr << "\t";
- fa->printsig (cerr);
- cerr << endl;
- }
+ vardecl* fa = fn->locals[k];
+ cerr << "\t";
+ fa->printsig (cerr);
cerr << endl;
}
-
- cerr << "globals:" << endl;
- for (unsigned k=0; k<f->globals.size(); k++)
+ cerr << endl;
+ }
+
+ for (unsigned j=0; j<f->probes.size(); j++)
+ {
+ probe* pn = f->probes[j];
+ cerr << "Probe " << *pn->tok << endl; // XXX: print probespec
+ cerr << "locals:" << endl;
+ for (unsigned k=0; k<pn->locals.size(); k++)
{
- vardecl* fa = f->globals[k];
+ vardecl* fa = pn->locals[k];
cerr << "\t";
fa->printsig (cerr);
cerr << endl;
}
cerr << endl;
}
+
+ cerr << "globals:" << endl;
+ for (unsigned k=0; k<f->globals.size(); k++)
+ {
+ vardecl* fa = f->globals[k];
+ cerr << "\t";
+ fa->printsig (cerr);
+ cerr << endl;
+ }
+ cerr << endl;
}
return rc;
diff --git a/staptree.cxx b/staptree.cxx
index 2bbdea9f..51ac8113 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -61,6 +61,18 @@ symboldecl::~symboldecl ()
}
+probe_point::probe_point ():
+ tok (0), prov (0)
+{
+}
+
+
+probe_point::component::component ():
+ arg (0)
+{
+}
+
+
vardecl::vardecl ()
{
}
@@ -301,21 +313,26 @@ void stapfile::print (ostream& o)
void probe::print (ostream& o)
{
o << "probe ";
- for (unsigned i=0; i<location.size(); i++)
+ for (unsigned i=0; i<locations.size(); i++)
{
- o << (i>0 ? ":" : "");
- location[i]->print (o);
+ o << (i>0 ? ", " : "");
+ locations[i]->print (o);
}
o << endl;
o << *body;
}
-void probe_point_spec::print (ostream& o)
+void probe_point::print (ostream& o)
{
- o << functor;
- if (arg)
- o << "(" << *arg << ")";
+ 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 << ")";
+ }
}
diff --git a/staptree.h b/staptree.h
index b38221bc..cb22969b 100644
--- a/staptree.h
+++ b/staptree.h
@@ -364,18 +364,26 @@ struct stapfile
};
-struct probe_point_spec // inherit from something or other?
-{
- string functor;
- const token* tok;
- literal* arg;
+class provider;
+struct probe_point
+{
+ struct component // XXX: sort of a restricted functioncall
+ {
+ string functor;
+ literal* arg;
+ component ();
+ };
+ vector<component*> components;
+ const token* tok; // points to first component's functor
+ provider* prov;
void print (ostream& o);
+ probe_point ();
};
struct probe
{
- vector<probe_point_spec*> location;
+ vector<probe_point*> locations;
const token* tok;
block* body;
vector<vardecl*> locals;
diff --git a/testsuite/parseko/five.stp b/testsuite/parseko/five.stp
new file mode 100755
index 00000000..1673a1e6
--- /dev/null
+++ b/testsuite/parseko/five.stp
@@ -0,0 +1,16 @@
+#! semtest
+
+probe foo( {
+}
+
+probe bar() {
+}
+
+probe baz.(1) {
+}
+
+probe faz(2), {
+}
+
+probe kaz,goo. {
+}
diff --git a/testsuite/parseko/six.stp b/testsuite/parseko/six.stp
new file mode 100755
index 00000000..2e8c8dbe
--- /dev/null
+++ b/testsuite/parseko/six.stp
@@ -0,0 +1,8 @@
+#! semtest
+
+probe foo {
+ a = -9999999999999999999999999;
+ b = 0xzoopoo;
+ c = 00011122233344455566677788;
+ d = 07777777777777777777777777;
+}
diff --git a/testsuite/parseok/five.stp b/testsuite/parseok/five.stp
new file mode 100755
index 00000000..a475807e
--- /dev/null
+++ b/testsuite/parseok/five.stp
@@ -0,0 +1,19 @@
+#! parsetest
+
+probe lkst("process_contextswitch") {}
+probe syscall("name").return {}
+probe syscall("*") {}
+probe kernel.function("wait_for_godot") {}
+probe kernel.function("name").line(10) {}
+probe kernel.source("mempool.c").line(5004) {}
+probe kernel.address(0xdeadbeef) {}
+probe kernel.module("driver.ko").function("name").return {}
+probe kernel.module("cpqarray.ko").jumptable("ida_fops") {}
+probe kernel.watch("datasymbol").write {}
+probe user("fche").inode("/bin/vi").function("refresh") {}
+probe user.inode("/lib/libc.so.6").function("malloc").return {}
+probe time.real.hz(500) {}
+probe time.virtual.jiffies(100) {}
+probe perfcounter("tlbmiss").count(4000) {}
+probe resource.freemembelow(50) {} # pages?
+probe begin {}
diff --git a/testsuite/parseok/four.stp b/testsuite/parseok/four.stp
new file mode 100755
index 00000000..d381b242
--- /dev/null
+++ b/testsuite/parseok/four.stp
@@ -0,0 +1,7 @@
+#! parsetest
+
+probe syscall ("foo").foo.bar , syscall ("bar"), syscall ("*").return
+{
+ $a = a$a = a$a$ = 0;
+}
+
diff --git a/testsuite/parseok/six.stp b/testsuite/parseok/six.stp
new file mode 100755
index 00000000..6fb9b764
--- /dev/null
+++ b/testsuite/parseok/six.stp
@@ -0,0 +1,8 @@
+#! parsetest
+
+probe one
+{
+ a = 1+01+0x1-1-01-0x1;
+ b = 2147483647;
+ c = -2147483647-1;
+}
diff --git a/testsuite/parseok/three.stp b/testsuite/parseok/three.stp
index b2628d4d..d2401877 100755
--- a/testsuite/parseok/three.stp
+++ b/testsuite/parseok/three.stp
@@ -1,6 +1,6 @@
#! parsetest
-probe kernel:systemcall("foo")
+probe syscall ("foo")
{
$a = a$a = a$a$ = 0;
}
diff --git a/testsuite/parseok/two.stp b/testsuite/parseok/two.stp
index 6ab3823e..b6b843de 100755
--- a/testsuite/parseok/two.stp
+++ b/testsuite/parseok/two.stp
@@ -1,6 +1,6 @@
#! parsetest
-probe kernel:systemcall("foo")
+probe syscall (231)
{
array[idx] << value;
if (global > 5) { global -- } else ;
@@ -11,7 +11,7 @@ function foo () {
return 0;
}
-probe systemtap:end
+probe end
{
foo ("value", 4+8);
}
diff --git a/testsuite/semko/one.stp b/testsuite/semko/one.stp
index 994bb451..7519dfc6 100755
--- a/testsuite/semko/one.stp
+++ b/testsuite/semko/one.stp
@@ -5,4 +5,4 @@ function stamp (syscall)
# no return expression => unknown function type
}
-probe kernel:syscall:read { stamp ("read"); }
+probe syscall (read) { stamp ("read"); }
diff --git a/testsuite/semok/four.stp b/testsuite/semok/four.stp
index e11b644a..c3b2a7d0 100755
--- a/testsuite/semok/four.stp
+++ b/testsuite/semok/four.stp
@@ -17,7 +17,7 @@ function stamp (syscall)
# probe kernel:syscall:read = kernel:function("sys_read");
-probe kernel:syscall:read
+probe syscall ("read")
{
stamp ("read");
}
diff --git a/testsuite/semok/one.stp b/testsuite/semok/one.stp
index fb7483e2..336e57d2 100755
--- a/testsuite/semok/one.stp
+++ b/testsuite/semok/one.stp
@@ -19,7 +19,7 @@ function stamp (syscall)
# probe kernel:syscall:read = kernel:function("sys_read");
-probe kernel:syscall:read
+probe syscall ("read")
{
stamp ("read");
}