summaryrefslogtreecommitdiffstats
path: root/tapsets.cxx
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2009-06-01 18:47:30 -0700
committerJosh Stone <jistone@redhat.com>2009-06-01 18:47:30 -0700
commit276465828851648edc5b56f762a0d100051c9e32 (patch)
tree25bc37f7800741949fd433cdaf25bbd198b2479e /tapsets.cxx
parentbec8cf694b0cd89dfa3d082e611326d7bcfad884 (diff)
downloadsystemtap-steved-276465828851648edc5b56f762a0d100051c9e32.tar.gz
systemtap-steved-276465828851648edc5b56f762a0d100051c9e32.tar.xz
systemtap-steved-276465828851648edc5b56f762a0d100051c9e32.zip
Move the blacklist functions into dwflpp
For a call like "stap -l 'syscall.*'", I found that ~10% of the time was spent compiling the blacklist regexps over again for each probe point. By moving this functionality into the kernel dwflpp instance, we can reuse the regexps and get an easy speed boost.
Diffstat (limited to 'tapsets.cxx')
-rw-r--r--tapsets.cxx324
1 files changed, 4 insertions, 320 deletions
diff --git a/tapsets.cxx b/tapsets.cxx
index e88928dc..f83924ab 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -43,7 +43,6 @@ extern "C" {
#include <dwarf.h>
#include <elf.h>
#include <obstack.h>
-#include <regex.h>
#include <glob.h>
#include <fnmatch.h>
#include <stdio.h>
@@ -550,19 +549,6 @@ struct dwarf_query : public base_query
int line,
Dwarf_Die *scope_die,
Dwarf_Addr addr);
- string get_blacklist_section(Dwarf_Addr addr);
-
- regex_t blacklist_func; // function/statement probes
- regex_t blacklist_func_ret; // only for .return probes
- regex_t blacklist_file; // file name
- void build_blacklist();
-
- bool blacklisted_p(const string& funcname,
- const string& filename,
- int line,
- const string& module,
- const string& section,
- Dwarf_Addr addr);
// Extracted parameters.
string function_val;
@@ -705,7 +691,6 @@ dwarf_query::dwarf_query(systemtap_session & sess,
else if (has_statement_str)
spec_type = parse_function_spec(statement_str_val);
- build_blacklist(); // XXX: why not reuse amongst dwarf_query instances?
dbinfo_reqt = assess_dbinfo_reqt();
query_done = false;
}
@@ -872,138 +857,6 @@ dwarf_query::handle_query_module()
}
-void
-dwarf_query::build_blacklist()
-{
- // No blacklist for userspace.
- if (has_process)
- return;
-
- // We build up the regexps in these strings
-
- // Add ^ anchors at the front; $ will be added just before regcomp.
-
- string blfn = "^(";
- string blfn_ret = "^(";
- string blfile = "^(";
-
- blfile += "kernel/kprobes.c"; // first alternative, no "|"
- blfile += "|arch/.*/kernel/kprobes.c";
- // Older kernels need ...
- blfile += "|include/asm/io.h";
- blfile += "|include/asm/bitops.h";
- // While newer ones need ...
- blfile += "|arch/.*/include/asm/io.h";
- blfile += "|arch/.*/include/asm/bitops.h";
- blfile += "|drivers/ide/ide-iops.c";
-
- // XXX: it would be nice if these blacklisted functions were pulled
- // in dynamically, instead of being statically defined here.
- // Perhaps it could be populated from script files. A "noprobe
- // kernel.function("...")" construct might do the trick.
-
- // Most of these are marked __kprobes in newer kernels. We list
- // them here (anyway) so the translator can block them on older
- // kernels that don't have the __kprobes function decorator. This
- // also allows detection of problems at translate- rather than
- // run-time.
-
- blfn += "atomic_notifier_call_chain"; // first blfn; no "|"
- blfn += "|default_do_nmi";
- blfn += "|__die";
- blfn += "|die_nmi";
- blfn += "|do_debug";
- blfn += "|do_general_protection";
- blfn += "|do_int3";
- blfn += "|do_IRQ";
- blfn += "|do_page_fault";
- blfn += "|do_sparc64_fault";
- blfn += "|do_trap";
- blfn += "|dummy_nmi_callback";
- blfn += "|flush_icache_range";
- blfn += "|ia64_bad_break";
- blfn += "|ia64_do_page_fault";
- blfn += "|ia64_fault";
- blfn += "|io_check_error";
- blfn += "|mem_parity_error";
- blfn += "|nmi_watchdog_tick";
- blfn += "|notifier_call_chain";
- blfn += "|oops_begin";
- blfn += "|oops_end";
- blfn += "|program_check_exception";
- blfn += "|single_step_exception";
- blfn += "|sync_regs";
- blfn += "|unhandled_fault";
- blfn += "|unknown_nmi_error";
-
- // Lots of locks
- blfn += "|.*raw_.*lock.*";
- blfn += "|.*read_.*lock.*";
- blfn += "|.*write_.*lock.*";
- blfn += "|.*spin_.*lock.*";
- blfn += "|.*rwlock_.*lock.*";
- blfn += "|.*rwsem_.*lock.*";
- blfn += "|.*mutex_.*lock.*";
- blfn += "|raw_.*";
- blfn += "|.*seq_.*lock.*";
-
- // atomic functions
- blfn += "|atomic_.*";
- blfn += "|atomic64_.*";
-
- // few other problematic cases
- blfn += "|get_bh";
- blfn += "|put_bh";
-
- // Experimental
- blfn += "|.*apic.*|.*APIC.*";
- blfn += "|.*softirq.*";
- blfn += "|.*IRQ.*";
- blfn += "|.*_intr.*";
- blfn += "|__delay";
- blfn += "|.*kernel_text.*";
- blfn += "|get_current";
- blfn += "|current_.*";
- blfn += "|.*exception_tables.*";
- blfn += "|.*setup_rt_frame.*";
-
- // PR 5759, CONFIG_PREEMPT kernels
- blfn += "|.*preempt_count.*";
- blfn += "|preempt_schedule";
-
- // These functions don't return, so return probes would never be recovered
- blfn_ret += "do_exit"; // no "|"
- blfn_ret += "|sys_exit";
- blfn_ret += "|sys_exit_group";
-
- // __switch_to changes "current" on x86_64 and i686, so return probes
- // would cause kernel panic, and it is marked as "__kprobes" on x86_64
- if (sess.architecture == "x86_64")
- blfn += "|__switch_to";
- if (sess.architecture == "i686")
- blfn_ret += "|__switch_to";
-
- blfn += ")$";
- blfn_ret += ")$";
- blfile += ")$";
-
- if (sess.verbose > 2)
- {
- clog << "blacklist regexps:" << endl;
- clog << "blfn: " << blfn << endl;
- clog << "blfn_ret: " << blfn_ret << endl;
- clog << "blfile: " << blfile << endl;
- }
-
- int rc = regcomp (& blacklist_func, blfn.c_str(), REG_NOSUB|REG_EXTENDED);
- if (rc) throw semantic_error ("blacklist_func regcomp failed");
- rc = regcomp (& blacklist_func_ret, blfn_ret.c_str(), REG_NOSUB|REG_EXTENDED);
- if (rc) throw semantic_error ("blacklist_func_ret regcomp failed");
- rc = regcomp (& blacklist_file, blfile.c_str(), REG_NOSUB|REG_EXTENDED);
- if (rc) throw semantic_error ("blacklist_file regcomp failed");
-}
-
-
function_spec_type
dwarf_query::parse_function_spec(string & spec)
{
@@ -1094,129 +947,6 @@ dwarf_query::parse_function_spec(string & spec)
}
-#if 0
-// Forward declaration.
-static int query_kernel_module (Dwfl_Module *, void **, const char *,
- Dwarf_Addr, void *);
-#endif
-
-
-// XXX: pull this into dwflpp
-static bool
-in_kprobes_function(systemtap_session& sess, Dwarf_Addr addr)
-{
- if (sess.sym_kprobes_text_start != 0 && sess.sym_kprobes_text_end != 0)
- {
- // If the probe point address is anywhere in the __kprobes
- // address range, we can't use this probe point.
- if (addr >= sess.sym_kprobes_text_start && addr < sess.sym_kprobes_text_end)
- return true;
- }
- return false;
-}
-
-
-bool
-dwarf_query::blacklisted_p(const string& funcname,
- const string& filename,
- int,
- const string& module,
- const string& section,
- Dwarf_Addr addr)
-{
- if (has_process)
- return false; // no blacklist for userspace
-
- if (section.substr(0, 6) == string(".init.") ||
- section.substr(0, 6) == string(".exit.") ||
- section.substr(0, 9) == string(".devinit.") ||
- section.substr(0, 9) == string(".devexit.") ||
- section.substr(0, 9) == string(".cpuinit.") ||
- section.substr(0, 9) == string(".cpuexit.") ||
- section.substr(0, 9) == string(".meminit.") ||
- section.substr(0, 9) == string(".memexit."))
- {
- // NB: module .exit. routines could be probed in theory:
- // if the exit handler in "struct module" is diverted,
- // first inserting the kprobes
- // then allowing the exit code to run
- // then removing these kprobes
- if (sess.verbose>1)
- clog << " skipping - init/exit";
- return true;
- }
-
- // Check for function marked '__kprobes'.
- if (module == TOK_KERNEL && in_kprobes_function(sess, addr))
- {
- if (sess.verbose>1)
- clog << " skipping - __kprobes";
- return true;
- }
-
- // Check probe point against blacklist.
- int goodfn = regexec (&blacklist_func, funcname.c_str(), 0, NULL, 0);
- if (has_return)
- goodfn = goodfn && regexec (&blacklist_func_ret, funcname.c_str(), 0, NULL, 0);
- int goodfile = regexec (&blacklist_file, filename.c_str(), 0, NULL, 0);
-
- if (! (goodfn && goodfile))
- {
- if (sess.guru_mode)
- {
- if (sess.verbose>1)
- clog << " guru mode enabled - ignoring blacklist";
- }
- else
- {
- if (sess.verbose>1)
- clog << " skipping - blacklisted";
- return true;
- }
- }
-
- // This probe point is not blacklisted.
- return false;
-}
-
-string dwarf_query::get_blacklist_section(Dwarf_Addr addr)
-{
- string blacklist_section;
- Dwarf_Addr bias;
- // We prefer dwfl_module_getdwarf to dwfl_module_getelf here,
- // because dwfl_module_getelf can force costly section relocations
- // we don't really need, while either will do for this purpose.
- Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (dw.module, &bias))
- ?: dwfl_module_getelf (dw.module, &bias));
-
- Dwarf_Addr offset = addr - bias;
- if (elf)
- {
- Elf_Scn* scn = 0;
- size_t shstrndx;
- dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx));
- while ((scn = elf_nextscn (elf, scn)) != NULL)
- {
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- if (! shdr) continue; // XXX error?
-
- if (!(shdr->sh_flags & SHF_ALLOC))
- continue;
-
- GElf_Addr start = shdr->sh_addr;
- GElf_Addr end = start + shdr->sh_size;
- if (! (offset >= start && offset < end))
- continue;
-
- blacklist_section = elf_strptr (elf, shstrndx, shdr->sh_name);
- break;
- }
- }
- return blacklist_section;
-}
-
-
void
dwarf_query::add_probe_point(const string& funcname,
const char* filename,
@@ -1225,40 +955,13 @@ dwarf_query::add_probe_point(const string& funcname,
Dwarf_Addr addr)
{
string reloc_section; // base section for relocation purposes
- Dwarf_Addr reloc_addr = addr; // relocated
+ Dwarf_Addr reloc_addr; // relocated
string blacklist_section; // linking section for blacklist purposes
const string& module = dw.module_name; // "kernel" or other
assert (! has_absolute); // already handled in dwarf_builder::build()
- if (!dw.module)
- {
- assert(module == TOK_KERNEL);
- reloc_section = "";
- blacklist_section = "";
- }
- else if (dwfl_module_relocations (dw.module) > 0)
- {
- // This is a relocatable module; libdwfl already knows its
- // sections, so we can relativize addr.
- int idx = dwfl_module_relocate_address (dw.module, &reloc_addr);
- const char* r_s = dwfl_module_relocation_info (dw.module, idx, NULL);
- if (r_s)
- reloc_section = r_s;
- blacklist_section = reloc_section;
-
- if(reloc_section == "" && dwfl_module_relocations (dw.module) == 1)
- {
- blacklist_section = this->get_blacklist_section(addr);
- reloc_section = ".dynamic";
- reloc_addr = addr;
- }
- }
- else
- {
- blacklist_section = this->get_blacklist_section(addr);
- reloc_section = ".absolute";
- }
+ reloc_addr = dw.relocate_address(addr, reloc_section, blacklist_section);
if (sess.verbose > 1)
{
@@ -1274,7 +977,8 @@ dwarf_query::add_probe_point(const string& funcname,
clog << " pc=0x" << hex << addr << dec;
}
- bool bad = blacklisted_p (funcname, filename, line, module, blacklist_section, addr);
+ bool bad = dw.blacklisted_p (funcname, filename, line, module,
+ blacklist_section, addr, has_return);
if (sess.verbose > 1)
clog << endl;
@@ -1777,26 +1481,6 @@ query_cu (Dwarf_Die * cudie, void * arg)
}
-#if 0
-static int
-query_kernel_module (Dwfl_Module *mod,
- void **,
- const char *name,
- Dwarf_Addr,
- void *arg)
-{
- if (TOK_KERNEL == name)
- {
- Dwfl_Module **m = (Dwfl_Module **)arg;
-
- *m = mod;
- return DWARF_CB_ABORT;
- }
- return DWARF_CB_OK;
-}
-#endif
-
-
static void
validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q)
{