From 2260f4e32eb4c0b4cc95e4bef8ccdc5dc66261af Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 15 Sep 2009 17:04:00 -0400 Subject: PR10642: fix wildcard-driven quadratic explosion of .return $$parms probes For $variables listed in .return probes, a synthetic probe is being created, for saving the named variable values at function entry. However, the probe point for this synthetic probe was copied naively, so that several problems could occur: - if the original probe point contained wildcards, then each synthetic one also did, and was therefore multiply derived later - if the probe point referred to a multiply instantiated function, the synthetic one was not directly identified with it (at the dwarf_addr level) Now the synthetic probe is created more carefully, bypassing any further derivation/expansion processing steps. * tapsets.cxx (dwarf_var_expanding_visitor): Change add_probe to add_call_probe field. (visit_target_symbol_saved_return): Store only the body of the synthetic probe. (dwarf_derived_probe ctor): Create intimately related dwarf_derived_probe for synthetic probe. (uprobe_derived_probe ctor): Ditto. --- tapsets.cxx | 91 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 47 insertions(+), 44 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 7912ed99..95c0deb9 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1760,12 +1760,12 @@ struct dwarf_var_expanding_visitor: public var_expanding_visitor Dwarf_Die *scope_die; Dwarf_Addr addr; block *add_block; - probe *add_probe; + block *add_call_probe; // synthesized from .return probes with saved $vars std::map return_ts_map; bool visited; dwarf_var_expanding_visitor(dwarf_query & q, Dwarf_Die *sd, Dwarf_Addr a): - q(q), scope_die(sd), addr(a), add_block(NULL), add_probe(NULL), visited(false) {} + q(q), scope_die(sd), addr(a), add_block(NULL), add_call_probe(NULL), visited(false) {} void visit_target_symbol_saved_return (target_symbol* e); void visit_target_symbol_context (target_symbol* e); void visit_target_symbol (target_symbol* e); @@ -2014,36 +2014,17 @@ dwarf_var_expanding_visitor::visit_target_symbol_saved_return (target_symbol* e) // global array we created. Create the entry probe, which will // look like this: // - // probe kernel.function("{function}") { + // probe kernel.function("{function}").call { // _dwarf_tvar_tid = tid() // _dwarf_tvar_{name}_{num}[_dwarf_tvar_tid, // ++_dwarf_tvar_{name}_{num}_ctr[_dwarf_tvar_tid]] // = ${param} // } - if (add_probe == NULL) + if (add_call_probe == NULL) { - add_probe = new probe; - add_probe->tok = e->tok; - - // We need the name of the current probe point, minus the - // ".return" (or anything after it, such as ".maxactive(N)"). - // Create a new probe point, copying all the components, - // stopping when we see the ".return" component. - probe_point* pp = new probe_point; - for (unsigned c = 0; c < q.base_loc->components.size(); c++) - { - if (q.base_loc->components[c]->functor == "return") - break; - else - pp->components.push_back(q.base_loc->components[c]); - } - pp->tok = e->tok; - pp->optional = q.base_loc->optional; - add_probe->locations.push_back(pp); - - add_probe->body = new block; - add_probe->body->tok = e->tok; + add_call_probe = new block; + add_call_probe->tok = e->tok; // Synthesize a functioncall to grab the thread id. functioncall* fc = new functioncall; @@ -2060,14 +2041,7 @@ dwarf_var_expanding_visitor::visit_target_symbol_saved_return (target_symbol* e) expr_statement* es = new expr_statement; es->tok = e->tok; es->value = a; - add_probe->body = new block(add_probe->body, es); - - vardecl* vd = new vardecl; - vd->tok = e->tok; - vd->name = tidsym->name; - vd->type = pe_long; - vd->set_arity(0); - add_probe->locals.push_back(vd); + add_call_probe = new block(add_call_probe, es); } // Save the value, like this: @@ -2093,7 +2067,7 @@ dwarf_var_expanding_visitor::visit_target_symbol_saved_return (target_symbol* e) es->tok = e->tok; es->value = a; - add_probe->body = new block(add_probe->body, es); + add_call_probe = new block(add_call_probe, es); // (4) Provide the '_dwarf_tvar_{name}_{num}_tmp' variable to // our parent so it can be used as a substitute for the target @@ -2732,13 +2706,29 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, // of code, add it to the start of the probe. if (v.add_block) this->body = new block(v.add_block, this->body); - // If when target-variable-expanding the probe, we added a new - // probe, add it in a new file to the list of files to be processed. - if (v.add_probe) + + // If when target-variable-expanding the probe, we need to synthesize a + // sibling function-entry probe. We don't go through the whole probe derivation + // business (PR10642) that could lead to wildcard/alias resolution, or for that + // dwarf-induced duplication. + if (v.add_call_probe) { - stapfile *f = new stapfile; - f->probes.push_back(v.add_probe); - q.sess.files.push_back(f); + assert (q.has_return && !q.has_call); + + // We temporarily replace q.base_probe. + statement* old_body = q.base_probe->body; + q.base_probe->body = v.add_call_probe; + q.has_return = false; + q.has_call = true; + + dwarf_derived_probe *synthetic = new dwarf_derived_probe (funcname, filename, line, + module, section, dwfl_addr, + addr, q, scope_die); + q.results.push_back (synthetic); + + q.has_return = true; + q.has_call = false; + q.base_probe->body = old_body; } } // else - null scope_die - $target variables will produce an error during translate phase @@ -4221,11 +4211,24 @@ uprobe_derived_probe::uprobe_derived_probe (const string& function, // If when target-variable-expanding the probe, we added a new // probe, add it in a new file to the list of files to be processed. - if (v.add_probe) + if (v.add_call_probe) { - stapfile *f = new stapfile; - f->probes.push_back(v.add_probe); - q.sess.files.push_back(f); + assert (q.has_return && !q.has_call); + + // We temporarily replace q.base_probe. + statement* old_body = q.base_probe->body; + q.base_probe->body = v.add_call_probe; + q.has_return = false; + q.has_call = true; + + uprobe_derived_probe *synthetic = new uprobe_derived_probe (function, filename, line, + module, pid, section, dwfl_addr, + addr, q, scope_die); + q.results.push_back (synthetic); + + q.has_return = true; + q.has_call = false; + q.base_probe->body = old_body; } } // else - null scope_die - $target variables will produce an error during translate phase -- cgit From f09d0d1e7fd437f6a3b8c21e4817de8af458c888 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 15 Sep 2009 18:15:20 -0700 Subject: Remove function comparison from label iteration We already have filtered functions and inlines, so just iterate in each of those to look for labels. * dwflpp.cxx (dwflpp::iterate_over_labels): Assume that the die we're looking at is already a matching function, and don't descend into inlined functions in this body. * tapsets.cxx (query_srcfile_label): Iterate through inlines too. (query_cu): Iterate over functions and inlines instead of the CU. --- tapsets.cxx | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index f5be7a4e..977a92fa 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1207,8 +1207,14 @@ query_srcfile_label (const dwarf_line_t& line, void * arg) for (func_info_map_t::iterator i = q->filtered_functions.begin(); i != q->filtered_functions.end(); ++i) if (q->dw.die_has_pc (i->die, addr)) - q->dw.iterate_over_labels (&i->die, q->label_val, q->function, - q, query_label, i->name); + q->dw.iterate_over_labels (&i->die, q->label_val, i->name, + q, query_label); + + for (inline_instance_map_t::iterator i = q->filtered_inlines.begin(); + i != q->filtered_inlines.end(); ++i) + if (q->dw.die_has_pc (i->die, addr)) + q->dw.iterate_over_labels (&i->die, q->label_val, i->name, + q, query_label); } static void @@ -1503,8 +1509,17 @@ query_cu (Dwarf_Die * cudie, void * arg) if (q->has_label) { if (q->line[0] == 0) // No line number specified - q->dw.iterate_over_labels (q->dw.cu, q->label_val, q->function, - q, query_label, ""); + { + for (func_info_map_t::iterator i = q->filtered_functions.begin(); + i != q->filtered_functions.end(); ++i) + q->dw.iterate_over_labels (&i->die, q->label_val, i->name, + q, query_label); + + for (inline_instance_map_t::iterator i = q->filtered_inlines.begin(); + i != q->filtered_inlines.end(); ++i) + q->dw.iterate_over_labels (&i->die, q->label_val, i->name, + q, query_label); + } else for (set::const_iterator i = q->filtered_srcfiles.begin(); i != q->filtered_srcfiles.end(); ++i) -- cgit From 6846cfc8a5cdb24fccb19037b27a180d2300ee09 Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Wed, 16 Sep 2009 21:05:00 -0400 Subject: * sdt.h (STAP_SEMAPHORE): New. Add guard to utrace probe points. * itrace.h (__access_process_vm): Moved from here... * runtime/access_process_vm.h: New. ...to here. * translate.cxx (translate_pass): Include access_process_vm.h * session.h (sdt_semaphore_addr): New. * tapsets.cxx (sdt_query::record_semaphore): New. Record sdt_semaphore_addr. (uprobe_derived_probe_group::emit_module_decls): Allow for uprobe guard variable to be set and unset. (uprobe_derived_probe_group::emit_module_decls): Likewise. (uprobe_derived_probe_group::emit_module_exit): Likewise. * tapset-utrace.cxx (utrace_derived_probe_group::emit_probe_decl): Likewise. (utrace_derived_probe_group::emit_module_decls): Likewise. (utrace_derived_probe_group::emit_module_exit): Likewise. --- tapsets.cxx | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 5 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 977a92fa..00927b2d 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3458,6 +3458,7 @@ private: probe * base_probe; probe_point * base_loc; + literal_map_t const & params; vector & results; string mark_name; @@ -3473,6 +3474,7 @@ private: bool get_next_probe(); void convert_probe(probe *base); + void record_semaphore(vector & results); void convert_location(probe *base, probe_point *location); }; @@ -3481,7 +3483,7 @@ sdt_query::sdt_query(probe * base_probe, probe_point * base_loc, dwflpp & dw, literal_map_t const & params, vector & results): base_query(dw, params), base_probe(base_probe), - base_loc(base_loc), results(results) + base_loc(base_loc), params(params), results(results) { assert(get_string_param(params, TOK_MARK, mark_name)); } @@ -3523,7 +3525,11 @@ sdt_query::handle_query_module() unsigned i = results.size(); if (probe_type == kprobe_type || probe_type == utrace_type) - derive_probes(sess, new_base, results); + { + derive_probes(sess, new_base, results); + record_semaphore(results); + } + else { literal_map_t params; @@ -3536,6 +3542,7 @@ sdt_query::handle_query_module() dwarf_query q(new_base, new_location, dw, params, results); q.has_mark = true; // enables mid-statement probing dw.iterate_over_modules(&query_module, &q); + record_semaphore(results); } if (sess.listing_mode) @@ -3666,6 +3673,28 @@ sdt_query::get_next_probe() } +void +sdt_query::record_semaphore (vector & results) +{ + int sym_count = dwfl_module_getsymtab(dw.module); + assert (sym_count >= 0); + for (int i = 0; i < sym_count; i++) + { + GElf_Sym sym; + GElf_Word shndxp; + char *sym_str = (char*)dwfl_module_getsym (dw.module, i, &sym, &shndxp); + if (strcmp(sym_str, string(probe_name + "_semaphore").c_str()) == 0) + { + string process_name; + derived_probe_builder::get_param(params, TOK_PROCESS, process_name); + for (unsigned int i = 0; i < results.size(); ++i) + sess.sdt_semaphore_addr.insert(make_pair(sym.st_value, results[i])); + break; + } + } +} + + void sdt_query::convert_probe (probe *base) { @@ -4392,6 +4421,8 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "unsigned long address;"; s.op->newline() << "const char *pp;"; s.op->newline() << "void (*ph) (struct context*);"; + s.op->newline() << "unsigned long sdt_sem_address;"; + s.op->newline() << "struct task_struct *tsk;"; s.op->newline() << "unsigned return_p:1;"; s.op->newline(-1) << "} stap_uprobe_specs [] = {"; s.op->indent(1); @@ -4405,6 +4436,21 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->line() << " .address=(unsigned long)0x" << hex << p->addr << dec << "ULL,"; s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ","; s.op->line() << " .ph=&" << p->name << ","; + map::iterator its; + if (s.sdt_semaphore_addr.empty()) + s.op->line() << " .sdt_sem_address=(unsigned long)0x0,"; + else + for (its = s.sdt_semaphore_addr.begin(); + its != s.sdt_semaphore_addr.end(); + its++) + { + if (p->module == ((struct uprobe_derived_probe*)(its->second))->module + && p->addr == ((struct uprobe_derived_probe*)(its->second))->addr) + { + s.op->line() << " .sdt_sem_address=(unsigned long)0x" << hex << its->first << dec << "ULL,"; + break; + } + } if (p->has_return) s.op->line() << " .return_p=1,"; s.op->line() << " },"; } @@ -4478,7 +4524,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "for (spec_index=0; spec_indexnewline(1) << "int handled_p = 0;"; s.op->newline() << "int slotted_p = 0;"; - s.op->newline() << "const struct stap_uprobe_spec *sups = &stap_uprobe_specs [spec_index];"; + s.op->newline() << "struct stap_uprobe_spec *sups = (struct stap_uprobe_spec*) &stap_uprobe_specs [spec_index];"; s.op->newline() << "int rc = 0;"; s.op->newline() << "int i;"; @@ -4558,6 +4604,16 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(-1) << "}"; s.op->newline(-1) << "}"; + //---------- + s.op->newline() << "if (sups->sdt_sem_address != 0) {"; + s.op->newline(1) << "size_t sdt_semaphore;"; + s.op->newline() << "sups->tsk = tsk;"; + s.op->newline() << "__access_process_vm (tsk, relocation + sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; + s.op->newline() << "sdt_semaphore += 1;"; + s.op->newline() << "__access_process_vm (tsk, relocation + sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; + s.op->newline(-1) << "}"; + //---------- + // close iteration over stap_uprobe_spec[] s.op->newline(-1) << "}"; @@ -4580,9 +4636,9 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "for (i=0; inewline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];"; - s.op->newline() << "const struct stap_uprobe_spec *sups;"; + s.op->newline() << "struct stap_uprobe_spec *sups;"; s.op->newline() << "if (sup->spec_index < 0) continue;"; // skip free uprobes slot - s.op->newline() << "sups = & stap_uprobe_specs[sup->spec_index];"; + s.op->newline() << "sups = (struct stap_uprobe_spec*) & stap_uprobe_specs[sup->spec_index];"; s.op->newline() << "mutex_lock (& stap_uprobes_lock);"; @@ -4642,6 +4698,16 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "mutex_unlock (& stap_uprobes_lock);"; + //---------- + s.op->newline() << "if (sups->sdt_sem_address != 0) {"; + s.op->newline(1) << "size_t sdt_semaphore;"; + s.op->newline() << "sups->tsk = tsk;"; + s.op->newline() << "__access_process_vm (tsk, sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; + s.op->newline() << "sdt_semaphore += 1;"; + s.op->newline() << "__access_process_vm (tsk, sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; + s.op->newline(-1) << "}"; + //---------- + // close iteration over stap_uprobes[] s.op->newline(-1) << "}"; @@ -4765,6 +4831,16 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline() << "const struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];"; s.op->newline() << "if (sup->spec_index < 0) continue;"; // free slot + //---------- + s.op->newline() << "if (sups->sdt_sem_address != 0) {"; + s.op->newline(1) << "size_t sdt_semaphore;"; + s.op->newline() << "__access_process_vm (sups->tsk, sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; + s.op->newline() << "sdt_semaphore -= 1;"; + s.op->newline() << "__access_process_vm (sups->tsk, sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; + s.op->newline(-1) << "}"; + //---------- + + s.op->newline() << "if (sups->return_p) {"; s.op->newline(1) << "#ifdef DEBUG_UPROBES"; s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"-uretprobe spec %d index %d pid %d addr %p\\n\", sup->spec_index, j, sup->up.pid, (void*) sup->up.vaddr);"; -- cgit From 7d6d0afc24b43829511f3f1d0aeff0fefff56b54 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Sep 2009 19:38:20 -0700 Subject: 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. --- tapsets.cxx | 177 ++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 106 insertions(+), 71 deletions(-) (limited to 'tapsets.cxx') 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 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(spec.substr(line_pos + 1)); + else + { + line_type = RANGE; + line[0] = lex_cast(spec.substr(line_pos + 1, + dash_pos - line_pos - 1)); + line[1] = lex_cast(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(string(i, e)); - else - { - line_type = RANGE; - line[0] = lex_cast(string(i, dash)); - line[1] = lex_cast(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; -- cgit