diff options
author | fche <fche> | 2005-10-18 02:28:00 +0000 |
---|---|---|
committer | fche <fche> | 2005-10-18 02:28:00 +0000 |
commit | b4ceace28084125ffbac795974319eaffa758147 (patch) | |
tree | 2e7a2052f6e3d016860dce9f7d40b6824a295076 | |
parent | 54efe513a4b01f433dba37f3106e4907028247f0 (diff) | |
download | systemtap-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-- | ChangeLog | 20 | ||||
-rw-r--r-- | elaborate.cxx | 196 | ||||
-rw-r--r-- | elaborate.h | 20 | ||||
-rw-r--r-- | parse.cxx | 58 | ||||
-rw-r--r-- | stapprobes.5.in | 11 | ||||
-rw-r--r-- | tapsets.cxx | 11 | ||||
-rwxr-xr-x | testsuite/semko/twentyone.stp | 2 | ||||
-rwxr-xr-x | testsuite/semko/twentythree.stp | 3 | ||||
-rwxr-xr-x | testsuite/semko/twentytwo.stp | 2 | ||||
-rwxr-xr-x | testsuite/semok/nineteen.stp | 10 |
10 files changed, 189 insertions, 144 deletions
@@ -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 @@ -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" } |