diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | Makefile.in | 3 | ||||
-rw-r--r-- | TODO | 27 | ||||
-rw-r--r-- | parse.cxx | 95 | ||||
-rw-r--r-- | parse.h | 2 | ||||
-rw-r--r-- | parsetest.cxx | 4 | ||||
-rwxr-xr-x | runtest.sh | 5 | ||||
-rw-r--r-- | semtest.cxx | 65 | ||||
-rw-r--r-- | staptree.cxx | 31 | ||||
-rw-r--r-- | staptree.h | 20 | ||||
-rwxr-xr-x | testsuite/parseko/five.stp | 16 | ||||
-rwxr-xr-x | testsuite/parseko/six.stp | 8 | ||||
-rwxr-xr-x | testsuite/parseok/five.stp | 19 | ||||
-rwxr-xr-x | testsuite/parseok/four.stp | 7 | ||||
-rwxr-xr-x | testsuite/parseok/six.stp | 8 | ||||
-rwxr-xr-x | testsuite/parseok/three.stp | 2 | ||||
-rwxr-xr-x | testsuite/parseok/two.stp | 4 | ||||
-rwxr-xr-x | testsuite/semko/one.stp | 2 | ||||
-rwxr-xr-x | testsuite/semok/four.stp | 2 | ||||
-rwxr-xr-x | testsuite/semok/one.stp | 2 |
21 files changed, 255 insertions, 83 deletions
@@ -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 @@ -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 + @@ -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"); @@ -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 << ")"; + } } @@ -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"); } |