summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfche <fche>2005-10-18 02:28:00 +0000
committerfche <fche>2005-10-18 02:28:00 +0000
commitb4ceace28084125ffbac795974319eaffa758147 (patch)
tree2e7a2052f6e3d016860dce9f7d40b6824a295076
parent54efe513a4b01f433dba37f3106e4907028247f0 (diff)
downloadsystemtap-steved-b4ceace28084125ffbac795974319eaffa758147.tar.gz
systemtap-steved-b4ceace28084125ffbac795974319eaffa758147.tar.xz
systemtap-steved-b4ceace28084125ffbac795974319eaffa758147.zip
2005-10-17 Frank Ch. Eigler <fche@elastic.org>
PR 1338. * parse.cx (parse_probe): Unconditionally visit parse_probe_point. (parse_probe_point): Accept "*" as component name. * stapprobes.5.in: Document this. * elaborate.cxx (derive_probes): Rewrite. Make top-level function. (match_node::find_and_build): New function to replace (find_builder): Removed. (match_key operator <): Correct one nasty typo. (match_node::bind): Refuse to bind "*" component names. (derived_probe_builder::build): Remove recursion output param. (alias_expandion_builder::build): Recurse to derive_probes instead. * elaborate.h: Corresponding changes. * tapsets.cxx: Ditto. (query_cu): Elide prologue finding for uninteresting CUs. * testsuite/semok/nineteen.stp: New test. * testsuite/semko/twentythree.stp: New test. * testsuite/semko/twentyone/two.stp: Fix -p2.
-rw-r--r--ChangeLog20
-rw-r--r--elaborate.cxx196
-rw-r--r--elaborate.h20
-rw-r--r--parse.cxx58
-rw-r--r--stapprobes.5.in11
-rw-r--r--tapsets.cxx11
-rwxr-xr-xtestsuite/semko/twentyone.stp2
-rwxr-xr-xtestsuite/semko/twentythree.stp3
-rwxr-xr-xtestsuite/semko/twentytwo.stp2
-rwxr-xr-xtestsuite/semok/nineteen.stp10
10 files changed, 189 insertions, 144 deletions
diff --git a/ChangeLog b/ChangeLog
index 269a5311..b30301a4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2005-10-17 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 1338.
+ * parse.cx (parse_probe): Unconditionally visit parse_probe_point.
+ (parse_probe_point): Accept "*" as component name.
+ * stapprobes.5.in: Document this.
+ * elaborate.cxx (derive_probes): Rewrite. Make top-level function.
+ (match_node::find_and_build): New function to replace
+ (find_builder): Removed.
+ (match_key operator <): Correct one nasty typo.
+ (match_node::bind): Refuse to bind "*" component names.
+ (derived_probe_builder::build): Remove recursion output param.
+ (alias_expandion_builder::build): Recurse to derive_probes instead.
+ * elaborate.h: Corresponding changes.
+ * tapsets.cxx: Ditto.
+ (query_cu): Elide prologue finding for uninteresting CUs.
+ * testsuite/semok/nineteen.stp: New test.
+ * testsuite/semko/twentythree.stp: New test.
+ * testsuite/semko/twentyone/two.stp: Fix -p2.
+
2005-10-17 Graydon Hoare <graydon@redhat.com>
* testsuite/semko/twentyone.stp: Check function doesn't match inline.
diff --git a/elaborate.cxx b/elaborate.cxx
index de10f7f2..1307880c 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -24,6 +24,17 @@ extern "C" {
using namespace std;
+template <typename OUT, typename IN> inline OUT
+lex_cast(IN const & in)
+{
+ stringstream ss;
+ OUT out;
+ if (!(ss << in && ss >> out))
+ throw runtime_error("bad lexical cast");
+ return out;
+}
+
+
// ------------------------------------------------------------------------
@@ -140,10 +151,10 @@ match_key::operator<(match_key const & other) const
{
return ((name < other.name)
- || (name == name
+ || (name == other.name
&& have_parameter < other.have_parameter)
- || (name == name
+ || (name == other.name
&& have_parameter == other.have_parameter
&& parameter_type < other.parameter_type));
}
@@ -159,6 +170,9 @@ match_node::match_node()
match_node *
match_node::bind(match_key const & k)
{
+ if (k.name == "*")
+ throw semantic_error("invalid use of wildcard probe point component");
+
map<match_key, match_node *>::const_iterator i = sub.find(k);
if (i != sub.end())
return i->second;
@@ -193,70 +207,89 @@ match_node::bind_num(string const & k)
return bind(match_key(k).with_number());
}
-derived_probe_builder *
-match_node::find_builder(vector<probe_point::component *> const & components,
- unsigned pos,
- vector< pair<string, literal *> > & parameters)
+
+void
+match_node::find_and_build (systemtap_session& s,
+ probe* p, probe_point *loc, unsigned pos,
+ vector<derived_probe *>& results)
{
- assert(pos <= components.size());
- if (pos == components.size())
+ assert (pos <= loc->components.size());
+ if (pos == loc->components.size()) // matched all probe point components so far
{
- // Probe_point ends here. We match iff we have
- // an "end" entry here. If we don't, it'll be null.
- return end;
+ derived_probe_builder *b = end; // may be 0 if only nested names are bound
+
+ if (! b)
+ {
+ string alternatives;
+ for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
+ alternatives += string(" ") + i->first.str();
+
+ throw semantic_error (string("probe point truncated at position ") +
+ lex_cast<string> (pos) +
+ " (follow:" + alternatives + ")");
+ }
+
+ map<string, literal *> param_map;
+ for (unsigned i=0; i<pos; i++)
+ param_map[loc->components[i]->functor] = loc->components[i]->arg;
+ // maybe 0
+
+ b->build (s, p, loc, param_map, results);
}
- else
+ else if (loc->components[pos]->functor == "*") // wildcard?
{
- // Probe_point contains a component here. We match iff there's
- // an entry in the sub table, and its value matches the rest
- // of the probe_point.
- match_key k(*components[pos]);
- if (0)
- clog << "searching for component " << k.str() << endl;
- map<match_key, match_node *>::const_iterator i = sub.find(k);
- if (i == sub.end())
- {
- if (0)
- clog << "no match found" << endl;
- return NULL;
- }
- else
- {
- if (0)
- clog << "matched " << k.str() << endl;
- derived_probe_builder * builder = NULL;
- if (k.have_parameter)
- {
- assert(components[pos]->arg);
- parameters.push_back(make_pair(components[pos]->functor,
- components[pos]->arg));
- }
- else
- {
- // store a "null parameter" for any component we run into, anyways
- literal_string *empty = NULL;
- parameters.push_back(make_pair(components[pos]->functor, empty));
- }
- builder = i->second->find_builder(components, pos+1, parameters);
- if (k.have_parameter && !builder)
- parameters.pop_back();
- return builder;
- }
- }
-}
+ // Recursively call derive_probes for all matches of the current
+ // key position. To do this, we have to perform almost an
+ // alias-level duplication of the probe body and synthesis of
+ // new probe_points.
+ probe * n = new probe();
+ n->tok = p->tok;
+ n->body = deep_copy_visitor::deep_copy(p->body);
-static void
-param_vec_to_map(vector< pair<string, literal *> > const & param_vec,
- map<string, literal *> & param_map)
-{
- for (vector< pair<string, literal *> >::const_iterator i = param_vec.begin();
- i != param_vec.end(); ++i)
+ // Construct N probe_point instances: one per wildcard match
+ for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
+ {
+ const match_key& match = i->first;
+ probe_point *loc2 = new probe_point;
+ loc2->tok = loc->tok;
+
+ // deep-copy probe point components, except for this wildcard position
+ for (unsigned k=0; k<loc->components.size(); k++)
+ if (pos != k)
+ loc2->components.push_back(new probe_point::component(loc->components[k]->functor,
+ loc->components[k]->arg));
+ else
+ // NB: we retain wildcard arg - foo.*(5).bar => foo.a(5).bar, foo.b(5).bar
+ loc2->components.push_back(new probe_point::component(match.name,
+ loc->components[k]->arg));
+ n->locations.push_back (loc2);
+ }
+
+ derive_probes (s, n, results, false);
+ }
+ else
{
- param_map[i->first] = i->second;
+ match_key match (* loc->components[pos]);
+ sub_map_iterator_t i = sub.find (match);
+ if (i == sub.end()) // no match
+ {
+ string alternatives;
+ for (sub_map_iterator_t i = sub.begin(); i != sub.end(); i++)
+ alternatives += string(" ") + i->first.str();
+
+ throw semantic_error (string("probe point mismatch at position ") +
+ lex_cast<string> (pos) +
+ " (alternatives:" + alternatives + ")");
+ }
+
+ match_node* subnode = i->second;
+ // recurse
+ subnode->find_and_build (s, p, loc, pos+1, results);
}
}
+
// ------------------------------------------------------------------------
// Alias probes
// ------------------------------------------------------------------------
@@ -275,7 +308,6 @@ alias_expansion_builder
probe * use,
probe_point * location,
std::map<std::string, literal *> const & parameters,
- vector<probe *> & results_to_expand_further,
vector<derived_probe *> & finished_results)
{
// We're going to build a new probe and wrap it up in an
@@ -311,8 +343,8 @@ alias_expansion_builder
statement *s = deep_copy_visitor::deep_copy(use->body->statements[i]);
n->body->statements.push_back(s);
}
-
- results_to_expand_further.push_back(n);
+
+ derive_probes (sess, n, finished_results, false);
}
};
@@ -388,59 +420,41 @@ recursion_guard
// The match-and-expand loop.
void
-symresolution_info::derive_probes (match_node * root,
- probe *p, vector<derived_probe*>& dps)
+derive_probes (systemtap_session& s,
+ probe *p, vector<derived_probe*>& dps,
+ bool exc_outermost)
{
- static unsigned depth=0;
- recursion_guard guard(depth);
-
for (unsigned i = 0; i < p->locations.size(); ++i)
{
probe_point *loc = p->locations[i];
- vector< pair<string, literal *> > param_vec;
- map<string, literal *> param_map;
- vector<probe *> re_expand;
-
+
try
{
- derived_probe_builder * builder =
- root->find_builder(loc->components, 0, param_vec);
-
- if (!builder)
- throw semantic_error ("no match for probe point family");
-
- param_vec_to_map(param_vec, param_map);
-
unsigned num_atbegin = dps.size();
- builder->build(session, p, loc, param_map, re_expand, dps);
-
- // Recursively expand any further-expanding results
- // XXX: ... or the build routine could get a reference to
- // this object and let it call derive_probes() internally
- if (!re_expand.empty())
- {
- for (unsigned j = 0; j < re_expand.size(); ++j)
- derive_probes(root, re_expand[j], dps);
- }
-
+ s.pattern_root->find_and_build (s, p, loc, 0, dps);
unsigned num_atend = dps.size();
- if (num_atbegin == num_atend) // nothing new derived!
+
+ if (exc_outermost && (num_atbegin == num_atend)) // nothing new derived!
throw semantic_error ("no match for probe point");
}
catch (const semantic_error& e)
{
- session.print_error (e);
+ // XXX: prefer not to print_error at every nest/unroll level
+ s.print_error (e);
cerr << " while: resolving probe point " << *loc << endl;
+ // if (! exc_outermost)
+ // throw;
}
}
}
+
+
// ------------------------------------------------------------------------
//
// Map usage checks
//
-
struct mutated_map_collector
: public traversing_visitor
{
@@ -622,7 +636,7 @@ semantic_pass_symbols (systemtap_session& s)
// much magic happens here: probe alias expansion,
// provider identification
- sym.derive_probes (s.pattern_root, p, dps);
+ derive_probes (s, p, dps);
for (unsigned j=0; j<dps.size(); j++)
{
diff --git a/elaborate.h b/elaborate.h
index e3683a27..b2eec8a2 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -33,9 +33,6 @@ public:
derived_probe* current_probe;
symresolution_info (systemtap_session& s);
- // XXX: instead in systemtap_session?
- void derive_probes (match_node * root, probe *p, std::vector<derived_probe*>& dps);
-
vardecl* find_var (const std::string& name, int arity);
functiondecl* find_function (const std::string& name, unsigned arity);
@@ -143,7 +140,6 @@ struct derived_probe_builder
probe* base,
probe_point* location,
std::map<std::string, literal*> const & parameters,
- std::vector<probe*> & results_to_expand_further,
std::vector<derived_probe*> & finished_results) = 0;
virtual ~derived_probe_builder() {}
@@ -174,15 +170,18 @@ match_key
class
match_node
{
- std::map<match_key, match_node*> sub;
+ typedef std::map<match_key, match_node*> sub_map_t;
+ typedef std::map<match_key, match_node*>::iterator sub_map_iterator_t;
+ sub_map_t sub;
derived_probe_builder* end;
public:
match_node();
- derived_probe_builder* find_builder(std::vector<probe_point::component*> const & components,
- unsigned pos,
- std::vector< std::pair<std::string, literal*> > & parameters);
-
+
+ void find_and_build (systemtap_session& s,
+ probe* p, probe_point *loc, unsigned pos,
+ std::vector<derived_probe *>& results);
+
match_node* bind(match_key const & k);
match_node* bind(std::string const & k);
match_node* bind_str(std::string const & k);
@@ -250,6 +249,9 @@ struct systemtap_session
int semantic_pass (systemtap_session& s);
+void derive_probes (systemtap_session& s,
+ probe *p, std::vector<derived_probe*>& dps,
+ bool exc_outermost = true);
#endif // ELABORATE_H
diff --git a/parse.cxx b/parse.cxx
index bbb209b8..dc9024c9 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -563,35 +563,28 @@ parser::parse_probe (std::vector<probe *> & probe_ret,
while (1)
{
- const token *t = peek ();
- if (t && t->type == tok_identifier)
- {
- probe_point * pp = parse_probe_point ();
-
- t = peek ();
- if (equals_ok && t
- && t->type == tok_operator && t->content == "=")
- {
- aliases.push_back(pp);
- next ();
- continue;
- }
- else if (t && t->type == tok_operator && t->content == ",")
- {
- locations.push_back(pp);
- equals_ok = false;
- next ();
- continue;
- }
- else if (t && t->type == tok_operator && t->content == "{")
- {
- locations.push_back(pp);
- break;
- }
- else
- throw parse_error ("expected ',' or '{'");
- // XXX: unify logic with that in parse_symbol()
- }
+ probe_point * pp = parse_probe_point ();
+
+ const token* t = peek ();
+ if (equals_ok && t
+ && t->type == tok_operator && t->content == "=")
+ {
+ aliases.push_back(pp);
+ next ();
+ continue;
+ }
+ else if (t && t->type == tok_operator && t->content == ",")
+ {
+ locations.push_back(pp);
+ equals_ok = false;
+ next ();
+ continue;
+ }
+ else if (t && t->type == tok_operator && t->content == "{")
+ {
+ locations.push_back(pp);
+ break;
+ }
else
throw parse_error ("expected probe point specifier");
}
@@ -838,13 +831,12 @@ parser::parse_probe_point ()
{
probe_point* pl = new probe_point;
- // XXX: add support for probe point aliases
- // e.g. probe alias = foo { ... }
while (1)
{
const token* t = next ();
- if (t->type != tok_identifier)
- throw parse_error ("expected identifier");
+ if (! (t->type == tok_identifier ||
+ (t->type == tok_operator && t->content == "*")))
+ throw parse_error ("expected identifier or '*'");
if (pl->tok == 0) pl->tok = t;
diff --git a/stapprobes.5.in b/stapprobes.5.in
index a5e20526..7a3a3edd 100644
--- a/stapprobes.5.in
+++ b/stapprobes.5.in
@@ -24,13 +24,16 @@ standard tapset scripts.
The general probe point syntax is a "dotted-functor" sequence. This
allows a breakdown of the event namespace into parts, somewhat like
the Domain Name System does on the Internet. Each component
-identifier may be parametrized by a string or number literal. These
-are all syntactically valid probe points:
+identifier may be parametrized by a string or number literal. A
+component part name may be replaced by a "*" character, to expand to
+other matching probe points. These are all syntactically valid probe
+points:
.SAMPLE
kernel.function("foo").return
syscall(22)
user.inode("/bin/vi").statement(0x2222)
end
+kernel.syscall.*
.ESAMPLE
.SS BEGIN/END
@@ -189,7 +192,9 @@ name in any of the USB drivers.
kernel.statement(0xc0044852)
refers to the first byte of the statement whose compiled instructions
include the given address in the kernel.
-
+.TP
+kernel.syscall.*.return
+refers to the group of probe aliases with any name in the third position
.SH SEE ALSO
.IR stap (1)
diff --git a/tapsets.cxx b/tapsets.cxx
index 36681f8c..5211d403 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -108,7 +108,6 @@ struct be_builder: public derived_probe_builder
probe * base,
probe_point * location,
std::map<std::string, literal *> const & parameters,
- vector<probe *> & results_to_expand_further,
vector<derived_probe *> & finished_results)
{
finished_results.push_back(new be_derived_probe(base, location, begin));
@@ -1407,7 +1406,6 @@ struct dwarf_builder: public derived_probe_builder
probe * base,
probe_point * location,
std::map<std::string, literal *> const & parameters,
- vector<probe *> & results_to_expand_further,
vector<derived_probe *> & finished_results);
};
@@ -2011,8 +2009,11 @@ query_cu (Dwarf_Die * cudie, void * arg)
// matching the query, and fill in the prologue endings of them
// all in a single pass.
q->dw.iterate_over_functions (query_dwarf_func, q);
- q->dw.resolve_prologue_endings (q->filtered_functions);
- q->dw.resolve_prologue_endings2 (q->filtered_functions);
+ if (! q->filtered_functions.empty()) // No functions in this CU to worry about?
+ {
+ q->dw.resolve_prologue_endings (q->filtered_functions);
+ q->dw.resolve_prologue_endings2 (q->filtered_functions);
+ }
if ((q->has_statement_str || q->has_function_str || q->has_inline_str)
&& (q->spec_type == function_file_and_line))
@@ -2754,7 +2755,6 @@ dwarf_builder::build(systemtap_session & sess,
probe * base,
probe_point * location,
std::map<std::string, literal *> const & parameters,
- vector<probe *> & results_to_expand_further,
vector<derived_probe *> & finished_results)
{
@@ -2916,7 +2916,6 @@ struct timer_builder: public derived_probe_builder
probe * base,
probe_point * location,
std::map<std::string, literal *> const & parameters,
- vector<probe *> &,
vector<derived_probe *> & finished_results)
{
int64_t jn, rn;
diff --git a/testsuite/semko/twentyone.stp b/testsuite/semko/twentyone.stp
index 9137a88b..c01725e2 100755
--- a/testsuite/semko/twentyone.stp
+++ b/testsuite/semko/twentyone.stp
@@ -1,4 +1,4 @@
-#! stap -p4
+#! stap -p2
# tests that an inline function is *not* matched using
# the function() pattern
diff --git a/testsuite/semko/twentythree.stp b/testsuite/semko/twentythree.stp
new file mode 100755
index 00000000..65b6b28f
--- /dev/null
+++ b/testsuite/semko/twentythree.stp
@@ -0,0 +1,3 @@
+#! stap -p2
+
+probe badalias.* = begin { }
diff --git a/testsuite/semko/twentytwo.stp b/testsuite/semko/twentytwo.stp
index cb67c896..3d2f6429 100755
--- a/testsuite/semko/twentytwo.stp
+++ b/testsuite/semko/twentytwo.stp
@@ -1,4 +1,4 @@
-#! stap -p4
+#! stap -p2
# tests that a non-inline function is *not* matched using
# the inline() pattern
diff --git a/testsuite/semok/nineteen.stp b/testsuite/semok/nineteen.stp
new file mode 100755
index 00000000..dcd9fb7e
--- /dev/null
+++ b/testsuite/semok/nineteen.stp
@@ -0,0 +1,10 @@
+#! stap -p2
+
+probe foo.a = bar.a { "alias a" }
+probe foo.b = bar.b { "alias b" }
+probe bar.a = begin { "begin" }
+probe bar.b = end { "end" }
+probe baz = bar.* { "wild aliases" } # baz expands to multiple aliases
+probe foo.* { "foo" } # refers to multiple aliases
+probe bar.* { "bar" } # refers to multiple probes
+probe baz { "baz" }