diff options
-rw-r--r-- | dwflpp.cxx | 55 | ||||
-rw-r--r-- | dwflpp.h | 4 | ||||
-rw-r--r-- | tapsets.cxx | 177 |
3 files changed, 162 insertions, 74 deletions
@@ -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) { @@ -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; |