* 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-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.
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
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) \
$(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
--- /dev/null
+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
+
#include "staptree.h"
#include "parse.h"
#include <cctype>
+#include <cstdlib>
#include <fstream>
+#include <cerrno>
+#include <climits>
using namespace std;
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
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;
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 ();
}
-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;
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");
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 ();
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)
--- /dev/null
+#! /bin/sh
+
+# Redirect stdout/stderr to /dev/null before invoking the given test
+
+exec $@ >/dev/null 2>&1
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;
}
+probe_point::probe_point ():
+ tok (0), prov (0)
+{
+}
+
+
+probe_point::component::component ():
+ arg (0)
+{
+}
+
+
vardecl::vardecl ()
{
}
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 << ")";
+ }
}
};
-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;
--- /dev/null
+#! semtest
+
+probe foo( {
+}
+
+probe bar() {
+}
+
+probe baz.(1) {
+}
+
+probe faz(2), {
+}
+
+probe kaz,goo. {
+}
--- /dev/null
+#! semtest
+
+probe foo {
+ a = -9999999999999999999999999;
+ b = 0xzoopoo;
+ c = 00011122233344455566677788;
+ d = 07777777777777777777777777;
+}
--- /dev/null
+#! 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 {}
--- /dev/null
+#! parsetest
+
+probe syscall ("foo").foo.bar , syscall ("bar"), syscall ("*").return
+{
+ $a = a$a = a$a$ = 0;
+}
+
--- /dev/null
+#! parsetest
+
+probe one
+{
+ a = 1+01+0x1-1-01-0x1;
+ b = 2147483647;
+ c = -2147483647-1;
+}
#! parsetest
-probe kernel:systemcall("foo")
+probe syscall ("foo")
{
$a = a$a = a$a$ = 0;
}
#! parsetest
-probe kernel:systemcall("foo")
+probe syscall (231)
{
array[idx] << value;
if (global > 5) { global -- } else ;
return 0;
}
-probe systemtap:end
+probe end
{
foo ("value", 4+8);
}
# no return expression => unknown function type
}
-probe kernel:syscall:read { stamp ("read"); }
+probe syscall (read) { stamp ("read"); }
# probe kernel:syscall:read = kernel:function("sys_read");
-probe kernel:syscall:read
+probe syscall ("read")
{
stamp ("read");
}
# probe kernel:syscall:read = kernel:function("sys_read");
-probe kernel:syscall:read
+probe syscall ("read")
{
stamp ("read");
}