summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2009-09-16 19:38:20 -0700
committerJosh Stone <jistone@redhat.com>2009-09-16 19:38:20 -0700
commit7d6d0afc24b43829511f3f1d0aeff0fefff56b54 (patch)
treefa0e55f71448e92074c5c5ef8bde4098bdf76fb7
parent04ddd303348c0ffb71c6f57eacb2282bd1d61b3a (diff)
downloadsystemtap-steved-7d6d0afc24b43829511f3f1d0aeff0fefff56b54.tar.gz
systemtap-steved-7d6d0afc24b43829511f3f1d0aeff0fefff56b54.tar.xz
systemtap-steved-7d6d0afc24b43829511f3f1d0aeff0fefff56b54.zip
PR10461: Match C++ scopes for namespaces and classes
The function spec for dwarf probes now supports scopes, so you can limit the probes to specific namespaces or classes. Multiple scopes can be specified, and they will be matched progressively outward. probe process("foo").function("std::vector<*>::*") { ... } probe process("foo").function("::global_function") { ... } * dwflpp.cxx (dwflpp::get_parent_scope): New, finds the containing scopes of the specified DIE. (dwflpp::function_scope_matches): New, checks that the scopes containing the function all match the given scope patterns. * tapsets.cxx (dwarf_query::parse_function_spec): Rewrite, now handles multiple scope separators too. (query_dwarf_func): Check that the functions scopes match.
-rw-r--r--dwflpp.cxx58
-rw-r--r--dwflpp.h3
-rw-r--r--tapsets.cxx177
3 files changed, 167 insertions, 71 deletions
diff --git a/dwflpp.cxx b/dwflpp.cxx
index 68e6e97b..a73c3c4c 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -266,6 +266,33 @@ dwflpp::function_name_matches(const string& pattern)
}
+bool
+dwflpp::function_scope_matches(const vector<string> scopes)
+{
+ // walk up the containing scopes
+ Dwarf_Die* die = function;
+ for (int i = scopes.size() - 1; i >= 0; --i)
+ {
+ die = get_parent_scope(die);
+
+ // check if this scope matches, and prepend it if so
+ // NB: a NULL die is the global scope, compared as ""
+ string name = dwarf_diename(die) ?: "";
+ if (name_has_wildcard(scopes[i]) ?
+ function_name_matches_pattern(name, scopes[i]) :
+ name == scopes[i])
+ function_name = name + "::" + function_name;
+ else
+ return false;
+
+ // make sure there's no more if we're at the global scope
+ if (!die && i > 0)
+ return false;
+ }
+ return true;
+}
+
+
static const char *offline_search_modname = NULL;
static int offline_search_match_p = 0;
@@ -591,6 +618,9 @@ dwflpp::cache_die_parents(cu_die_parent_cache_t* parents, Dwarf_Die* die)
case DW_TAG_entry_point:
case DW_TAG_inlined_subroutine:
case DW_TAG_subprogram:
+ case DW_TAG_namespace:
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
parents->insert(make_pair(child.addr, *die));
cache_die_parents(parents, &child);
break;
@@ -743,6 +773,34 @@ dwflpp::getscopes(Dwarf_Addr pc)
}
+Dwarf_Die*
+dwflpp::get_parent_scope(Dwarf_Die* die)
+{
+ Dwarf_Die specification;
+ if (dwarf_attr_die(die, DW_AT_specification, &specification))
+ die = &specification;
+
+ cu_die_parent_cache_t *parents = get_die_parents();
+ cu_die_parent_cache_t::iterator it = parents->find(die->addr);
+ while (it != parents->end())
+ {
+ Dwarf_Die* scope = &it->second;
+ switch (dwarf_tag (scope))
+ {
+ case DW_TAG_namespace:
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ return scope;
+
+ default:
+ break;
+ }
+ it = parents->find(scope->addr);
+ }
+ return NULL;
+}
+
+
int
dwflpp::global_alias_caching_callback(Dwarf_Die *die, void *arg)
{
diff --git a/dwflpp.h b/dwflpp.h
index 87bd6eba..5f04d824 100644
--- a/dwflpp.h
+++ b/dwflpp.h
@@ -192,6 +192,7 @@ struct dwflpp
bool function_name_matches_pattern(const std::string& name, const std::string& pattern);
bool function_name_matches(const std::string& pattern);
+ bool function_scope_matches(const std::vector<std::string> scopes);
void iterate_over_modules(int (* callback)(Dwfl_Module *, void **,
const char *, Dwarf_Addr,
@@ -304,6 +305,8 @@ private:
void cache_die_parents(cu_die_parent_cache_t* parents, Dwarf_Die* die);
cu_die_parent_cache_t *get_die_parents();
+ Dwarf_Die* get_parent_scope(Dwarf_Die* die);
+
/* The global alias cache is used to resolve any DIE found in a
* module that is stubbed out with DW_AT_declaration with a defining
* DIE found in a different module. The current assumption is that
diff --git a/tapsets.cxx b/tapsets.cxx
index 977a92fa..dd941251 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -591,8 +591,9 @@ struct dwarf_query : public base_query
enum dbinfo_reqt dbinfo_reqt;
enum dbinfo_reqt assess_dbinfo_reqt();
- function_spec_type parse_function_spec(string & spec);
+ void parse_function_spec(const string & spec);
function_spec_type spec_type;
+ vector<string> scopes;
string function;
string file;
line_t line_type;
@@ -697,9 +698,9 @@ dwarf_query::dwarf_query(probe * base_probe,
has_mark = false;
if (has_function_str)
- spec_type = parse_function_spec(function_str_val);
+ parse_function_spec(function_str_val);
else if (has_statement_str)
- spec_type = parse_function_spec(statement_str_val);
+ parse_function_spec(statement_str_val);
dbinfo_reqt = assess_dbinfo_reqt();
query_done = false;
@@ -869,93 +870,124 @@ dwarf_query::handle_query_module()
}
-function_spec_type
-dwarf_query::parse_function_spec(string & spec)
+void
+dwarf_query::parse_function_spec(const string & spec)
{
- string::const_iterator i = spec.begin(), e = spec.end();
-
- function.clear();
- file.clear();
- line[0] = 0;
- line[1] = 0;
+ size_t src_pos, line_pos, dash_pos, scope_pos, next_scope_pos;
- while (i != e && *i != '@')
+ // look for named scopes
+ scope_pos = 0;
+ next_scope_pos = spec.find("::");
+ while (next_scope_pos != string::npos)
{
- if (*i == ':' || *i == '+')
- goto bad;
- function += *i++;
+ scopes.push_back(spec.substr(scope_pos, next_scope_pos - scope_pos));
+ scope_pos = next_scope_pos + 2;
+ next_scope_pos = spec.find("::", scope_pos);
}
- if (i == e)
+ // look for a source separator
+ src_pos = spec.find('@', scope_pos);
+ if (src_pos == string::npos)
{
- if (sess.verbose>2)
- clog << "parsed '" << spec
- << "' -> func '" << function
- << "'\n";
- return function_alone;
+ function = spec.substr(scope_pos);
+ spec_type = function_alone;
}
-
- if (i++ == e)
- goto bad;
-
- while (i != e && *i != ':' && *i != '+')
- file += *i++;
- if (*i == ':')
+ else
{
- if (*(i + 1) == '*')
- line_type = WILDCARD;
+ function = spec.substr(scope_pos, src_pos - scope_pos);
+
+ // look for a line-number separator
+ line_pos = spec.find_first_of(":+", src_pos);
+ if (line_pos == string::npos)
+ {
+ file = spec.substr(src_pos + 1);
+ spec_type = function_and_file;
+ }
else
- line_type = ABSOLUTE;
- }
- else if (*i == '+')
- line_type = RELATIVE;
+ {
+ file = spec.substr(src_pos + 1, line_pos - src_pos - 1);
+
+ // classify the line spec
+ spec_type = function_file_and_line;
+ if (spec[line_pos] == '+')
+ line_type = RELATIVE;
+ else if (spec[line_pos + 1] == '*' &&
+ spec.length() == line_pos + 2)
+ line_type = WILDCARD;
+ else
+ line_type = ABSOLUTE;
- if (i == e)
- {
- if (sess.verbose>2)
- clog << "parsed '" << spec
- << "' -> func '"<< function
- << "', file '" << file
- << "'\n";
- return function_and_file;
+ if (line_type != WILDCARD)
+ try
+ {
+ // try to parse either N or N-M
+ dash_pos = spec.find('-', line_pos + 1);
+ if (dash_pos == string::npos)
+ line[0] = line[1] = lex_cast<int>(spec.substr(line_pos + 1));
+ else
+ {
+ line_type = RANGE;
+ line[0] = lex_cast<int>(spec.substr(line_pos + 1,
+ dash_pos - line_pos - 1));
+ line[1] = lex_cast<int>(spec.substr(dash_pos + 1));
+ }
+ }
+ catch (runtime_error & exn)
+ {
+ goto bad;
+ }
+ }
}
- if (i++ == e)
+ if (function.empty() ||
+ (spec_type != function_alone && file.empty()))
goto bad;
- try
+ if (sess.verbose > 2)
{
- if (line_type != WILDCARD)
- {
- string::const_iterator dash = i;
+ clog << "parsed '" << spec << "'";
- while (dash != e && *dash != '-')
- dash++;
- if (dash == e)
- line[0] = line[1] = lex_cast<int>(string(i, e));
- else
- {
- line_type = RANGE;
- line[0] = lex_cast<int>(string(i, dash));
- line[1] = lex_cast<int>(string(dash + 1, e));
- }
- }
+ if (!scopes.empty())
+ clog << ", scope '" << scopes[0] << "'";
+ for (unsigned i = 1; i < scopes.size(); ++i)
+ clog << "::'" << scopes[i] << "'";
- if (sess.verbose>2)
- clog << "parsed '" << spec
- << "' -> func '"<< function
- << "', file '" << file
- << "', line " << line << "\n";
- return function_file_and_line;
- }
- catch (runtime_error & exn)
- {
- goto bad;
+ clog << ", func '" << function << "'";
+
+ if (spec_type != function_alone)
+ clog << ", file '" << file << "'";
+
+ if (spec_type == function_file_and_line)
+ {
+ clog << ", line ";
+ switch (line_type)
+ {
+ case ABSOLUTE:
+ clog << line[0];
+ break;
+
+ case RELATIVE:
+ clog << "+" << line[0];
+ break;
+
+ case RANGE:
+ clog << line[0] << " - " << line[1];
+ break;
+
+ case WILDCARD:
+ clog << "*";
+ break;
+ }
+ }
+
+ clog << endl;
}
- bad:
- throw semantic_error("malformed specification '" + spec + "'",
- base_probe->tok);
+ return;
+
+bad:
+ throw semantic_error("malformed specification '" + spec + "'",
+ base_probe->tok);
}
@@ -1335,6 +1367,9 @@ query_dwarf_func (Dwarf_Die * func, base_query * bq)
{
q->dw.focus_on_function (func);
+ if (!q->dw.function_scope_matches(q->scopes))
+ return DWARF_CB_OK;
+
// make sure that this function address hasn't
// already been matched under an aliased name
Dwarf_Addr addr;