summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dwflpp.cxx55
-rw-r--r--dwflpp.h4
-rw-r--r--tapsets.cxx177
3 files changed, 162 insertions, 74 deletions
diff --git a/dwflpp.cxx b/dwflpp.cxx
index ee13d0b2..a73c3c4c 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -267,9 +267,29 @@ dwflpp::function_name_matches(const string& pattern)
bool
-dwflpp::function_name_final_match(const string& pattern)
+dwflpp::function_scope_matches(const vector<string> scopes)
{
- return module_name_final_match (pattern);
+ // 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;
}
@@ -598,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;
@@ -750,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 ab2ffe25..5f04d824 100644
--- a/dwflpp.h
+++ b/dwflpp.h
@@ -192,7 +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_name_final_match(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,
@@ -305,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 00927b2d..53f8ace5 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;