summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfche <fche>2007-03-30 19:17:02 +0000
committerfche <fche>2007-03-30 19:17:02 +0000
commitb8da0ad19d9dfcf88c4cd6dcf7b8aa73fc5016d7 (patch)
tree82225c0ef08f075dc0a5e9a8d59ed3d37a072b1c
parent3be43eac84e5819b72dd311c3283ef2ea5bb1d83 (diff)
downloadsystemtap-steved-b8da0ad19d9dfcf88c4cd6dcf7b8aa73fc5016d7.tar.gz
systemtap-steved-b8da0ad19d9dfcf88c4cd6dcf7b8aa73fc5016d7.tar.xz
systemtap-steved-b8da0ad19d9dfcf88c4cd6dcf7b8aa73fc5016d7.zip
2007-03-30 Frank Ch. Eigler <fche@redhat.com>
PR 1570 * NEWS: Document probe handler language change re. inline functions. * stapprobes.5.in: Likewise. * tapsets.cxx: Many changes to simplify caches and implement new handling of inline functions, removed of stubs for future probes. * elaborate.cxx (derived_probe printsig_nested): New function. * elaborate.h: Declare it. * main.cxx (usage): Clarify "-r" meaning. (main): Tweak related "-p 4" message. 2007-03-30 Frank Ch. Eigler <fche@elastic.org> PR 1570. * memory.stp, scheduler.stp, signal.stp, LKET/signal.stp: Adapt to .inline -> .function change. 2007-03-30 Frank Ch. Eigler <fche@elastic.org> PR 1570 * */*.stp: Adapt to .inline -> .function change. * lib/stap_run.exp, stap_run2.exp, stap_run_binary.exp: Shorten pass/fail dejagnu log lines. * systemtap.syscall/sys.stp, test.tcl: Make slightly more compatible and failure more verbose.
-rw-r--r--ChangeLog12
-rw-r--r--NEWS7
-rw-r--r--elaborate.cxx36
-rw-r--r--elaborate.h4
-rw-r--r--loc2c.c2
-rw-r--r--main.cxx6
-rw-r--r--stapprobes.5.in18
-rw-r--r--tapset/ChangeLog8
-rwxr-xr-xtapset/LKET/signal.stp3
-rw-r--r--tapset/memory.stp4
-rw-r--r--tapset/scheduler.stp8
-rw-r--r--tapset/signal.stp3
-rw-r--r--tapsets.cxx780
-rw-r--r--testsuite/ChangeLog9
-rwxr-xr-xtestsuite/buildok/six.stp2
-rw-r--r--testsuite/lib/stap_run.exp14
-rw-r--r--testsuite/lib/stap_run2.exp10
-rw-r--r--testsuite/lib/stap_run_binary.exp10
-rwxr-xr-xtestsuite/semko/twentytwo.stp2
-rwxr-xr-xtestsuite/semok/twenty.stp6
-rw-r--r--testsuite/systemtap.base/probefunc.exp4
-rw-r--r--testsuite/systemtap.stress/all_kernel_functions.exp10
-rw-r--r--testsuite/systemtap.stress/whitelist.exp1
-rwxr-xr-xtestsuite/systemtap.syscall/sys.stp4
-rwxr-xr-xtestsuite/systemtap.syscall/test.tcl5
25 files changed, 432 insertions, 536 deletions
diff --git a/ChangeLog b/ChangeLog
index 97a83ca0..c5356b02 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2007-03-30 Frank Ch. Eigler <fche@redhat.com>
+
+ PR 1570
+ * NEWS: Document probe handler language change re. inline functions.
+ * stapprobes.5.in: Likewise.
+ * tapsets.cxx: Many changes to simplify caches and implement new
+ handling of inline functions, removed of stubs for future probes.
+ * elaborate.cxx (derived_probe printsig_nested): New function.
+ * elaborate.h: Declare it.
+ * main.cxx (usage): Clarify "-r" meaning.
+ (main): Tweak related "-p 4" message.
+
2007-03-30 David Smith <dsmith@redhat.com>
PR 2341
diff --git a/NEWS b/NEWS
index 9963a81c..8ad06250 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,12 @@
* What's new since version 0.5.13?
+- The way in which systemtap resolves function/inline probes has changed:
+ .function(...) - now refers to all functions, inlined or not
+ .inline(...) - is deprecated, use instead:
+ .function(...).inline - filters function() to only inlined instances
+ .function(...).call - filters function() to only non-inlined instances
+ .function(...).return - as before, but now pairs best with .function().call
+ .statement() is unchanged.
* What's new since version 0.5.12?
diff --git a/elaborate.cxx b/elaborate.cxx
index be0cfcec..8ec376c0 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -62,8 +62,42 @@ derived_probe::derived_probe (probe *p, probe_point *l):
}
+void
+derived_probe::printsig (ostream& o) const
+{
+ probe::printsig (o);
+ printsig_nested (o);
+}
+
+void
+derived_probe::printsig_nested (ostream& o) const
+{
+ // We'd like to enclose the probe derivation chain in a /* */
+ // comment delimiter. But just printing /* base->printsig() */ is
+ // not enough, since base might itself be a derived_probe. So we,
+ // er, "cleverly" encode our nesting state as a formatting flag for
+ // the ostream.
+ ios::fmtflags f = o.flags (ios::internal);
+ if (f & ios::internal)
+ {
+ // already nested
+ o << " <- ";
+ base->printsig (o);
+ }
+ else
+ {
+ // outermost nesting
+ o << " /* <- ";
+ base->printsig (o);
+ o << " */";
+ }
+ // restore flags
+ (void) o.flags (f);
+}
+
+
probe_point*
-derived_probe::sole_location ()
+derived_probe::sole_location () const
{
if (locations.size() == 0)
throw semantic_error ("derived_probe with no locations", this->tok);
diff --git a/elaborate.h b/elaborate.h
index 9ad3c038..65ccb2f6 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -115,7 +115,9 @@ struct derived_probe: public probe
virtual probe* basest () { return base->basest(); }
virtual ~derived_probe () {}
virtual void join_group (systemtap_session& s) = 0;
- virtual probe_point* sole_location ();
+ virtual probe_point* sole_location () const;
+ virtual void printsig (std::ostream &o) const;
+ void printsig_nested (std::ostream &o) const;
virtual void emit_probe_context_vars (translator_output*) {}
// From within unparser::emit_common_header, add any extra variables
diff --git a/loc2c.c b/loc2c.c
index d7aa1273..f940fb0a 100644
--- a/loc2c.c
+++ b/loc2c.c
@@ -1385,7 +1385,7 @@ translate_base_store (struct obstack *pool, int indent, Dwarf_Word byte_size,
char piece[sizeof "u.pieces.p" + 20] = "u.pieces.p";
struct location *p;
for (p = store_loc->pieces; p != NULL; p = p->next)
- {
+ {
struct location *newp = obstack_alloc (pool, sizeof *newp);
*newp = *p;
newp->next = NULL;
diff --git a/main.cxx b/main.cxx
index b15c9185..50d6a792 100644
--- a/main.cxx
+++ b/main.cxx
@@ -90,7 +90,7 @@ usage (systemtap_session& s, int exitcode)
<< " -D NM=VAL emit macro definition into generated C code" << endl
<< " -R DIR look in DIR for runtime, instead of" << endl
<< " " << s.runtime_path << endl
- << " -r RELEASE use kernel RELEASE, instead of "
+ << " -r RELEASE cross-compile to kernel RELEASE, instead of "
<< s.kernel_release << endl
<< " -m MODULE set probe module name, instead of "
<< s.module_name << endl
@@ -426,8 +426,8 @@ main (int argc, char * const argv [])
if (s.last_pass > 4 && release_changed)
{
- cerr << ("Warning: changing last pass to 4 since the kernel release"
- " has changed.") << endl;
+ if (s.verbose)
+ cerr << "Warning: changing last pass to 4 since cross-compiling" << endl;
s.last_pass = 4;
}
diff --git a/stapprobes.5.in b/stapprobes.5.in
index 9f97ef01..0df9a893 100644
--- a/stapprobes.5.in
+++ b/stapprobes.5.in
@@ -157,10 +157,13 @@ variant places a probe at the moment of return from the named function, so
the return value is available as the "$return" context variable.
The
.B .inline
-variant is similar to
+modifier for
.B .function
-but probes inline functions. Inline functions do not have an identifiable
-return point, so
+filters the results to include only instances of inlined functions.
+The
+.B .call
+modifier selects the opposite subset. Inline functions do not have an
+identifiable return point, so
.B .return
is not supported on
.B .inline
@@ -171,15 +174,20 @@ that are visible there.
.SAMPLE
kernel.function(PATTERN)
.br
+kernel.function(PATTERN).call
+.br
kernel.function(PATTERN).return
.br
-kernel.inline(PATTERN)
+kernel.function(PATTERN).inline
.br
module(MPATTERN).function(PATTERN)
.br
+module(MPATTERN).function(PATTERN).call
+.br
module(MPATTERN).function(PATTERN).return
.br
-module(MPATTERN).inline(PATTERN)
+module(MPATTERN).function(PATTERN).inline
+.br
.br
kernel.statement(PATTERN)
.br
diff --git a/tapset/ChangeLog b/tapset/ChangeLog
index 4b122b56..6ce31780 100644
--- a/tapset/ChangeLog
+++ b/tapset/ChangeLog
@@ -1,3 +1,9 @@
+2007-03-30 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 1570.
+ * memory.stp, scheduler.stp, signal.stp, LKET/signal.stp: Adapt
+ to .inline -> .function change.
+
2007-03-09 Pierre Peiffer <pierre.peiffer@bull.net>
* nfsd.stp (nfsd.dispatch): Change initialization of variable
@@ -17,7 +23,7 @@
* syscalls.stp, s390x/syscall.stp: Created an s390x version of
syscall.mmap, syscall.mmap2, syscall.mmap.return, syscall.mmap2.return.
-2007-02-09 Frank Ch. Eigler <fche@elastic.org>
+2007-02-09 Fr ank Ch. Eigler <fche@elastic.org>
* conversions.stp (*): Make errmsg usage uniform.
diff --git a/tapset/LKET/signal.stp b/tapset/LKET/signal.stp
index 28b4a2b9..1de4da1f 100755
--- a/tapset/LKET/signal.stp
+++ b/tapset/LKET/signal.stp
@@ -240,8 +240,7 @@ function log_signal_pending_return(ret:long)
*
*/
/*
-probe signal.handle = kernel.function("handle_signal")?,
- kernel.inline("handle_signal")?
+probe signal.handle = kernel.function("handle_signal")
{
sig = $sig
sig_name = _signal_name($sig)
diff --git a/tapset/memory.stp b/tapset/memory.stp
index b66e1eb2..a3ed628f 100644
--- a/tapset/memory.stp
+++ b/tapset/memory.stp
@@ -76,7 +76,7 @@ probe vm.write_shared = kernel.function("do_wp_page") {
* zero - boolean indicating whether it is a zero page
* (can do a clear instead of a copy).
*/
-probe vm.write_shared_copy = kernel.inline("copy_cow_page")? {
+probe vm.write_shared_copy = kernel.function("copy_cow_page")? {
address = $address
zero = _IS_ZERO_PAGE($from, address);
}
@@ -93,7 +93,7 @@ probe vm.write_shared_copy = kernel.inline("copy_cow_page")? {
* address - the requested address
* length - the length of the memory segment
*/
-probe vm.mmap = kernel.inline("do_mmap"), kernel.inline("do_mmap2")? {
+probe vm.mmap = kernel.function("do_mmap"), kernel.function("do_mmap2")? {
address = $addr
length = $len
}
diff --git a/tapset/scheduler.stp b/tapset/scheduler.stp
index fe645a66..6c8d5d17 100644
--- a/tapset/scheduler.stp
+++ b/tapset/scheduler.stp
@@ -33,7 +33,7 @@ function __is_idle:long()
* idle - boolean indicating whether current is the idle process
*/
probe scheduler.cpu_off
- = kernel.inline("context_switch")
+ = kernel.function("context_switch")
{
task_prev = $prev
task_next = $next
@@ -53,7 +53,7 @@ probe scheduler.cpu_off
* idle - boolean indicating whether current is the idle process
*/
probe scheduler.cpu_on
- = kernel.inline("finish_task_switch")
+ = kernel.function("finish_task_switch")
{
task_prev = $prev
idle = __is_idle()
@@ -89,7 +89,7 @@ probe scheduler.tick = kernel.function("scheduler_tick")
* cpu_from - the cpu that is losing the task
* cpu_to - the cpu that is claiming the task
*/
-probe scheduler.migrate = kernel.inline("pull_task") {
+probe scheduler.migrate = kernel.function("pull_task") {
task = $p
cpu_from = $p->thread_info->cpu
cpu_to = $this_cpu
@@ -104,7 +104,7 @@ probe scheduler.migrate = kernel.inline("pull_task") {
* Context:
* The cpu looking for more work.
*/
-probe scheduler.balance = kernel.inline("idle_balance")? {}
+probe scheduler.balance = kernel.function("idle_balance")? {}
/* probe scheduler.ctxswitch
diff --git a/tapset/signal.stp b/tapset/signal.stp
index 33a2202c..bc4a0551 100644
--- a/tapset/signal.stp
+++ b/tapset/signal.stp
@@ -371,8 +371,7 @@ probe signal.pending.return = kernel.function("do_sigpending").return
* regs : Address in the Kernel Mode stack area
*
*/
-probe signal.handle = kernel.function("handle_signal")?,
- kernel.inline("handle_signal")?
+probe signal.handle = kernel.function("handle_signal")
{
sig = $sig
sig_name = _signal_name($sig)
diff --git a/tapsets.cxx b/tapsets.cxx
index e6bc7a47..f71f6df5 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -309,7 +309,8 @@ be_derived_probe_group::emit_module_decls (systemtap_session& s)
void
be_derived_probe_group::emit_module_init (systemtap_session& s)
{
- // if (probes.empty()) return;
+ if (probes.empty()) return;
+
bool have_begin_probes = false;
sort(probes.begin(), probes.end(), be_derived_probe::comp);
for (unsigned i=0; i < probes.size (); i++)
@@ -328,7 +329,8 @@ be_derived_probe_group::emit_module_init (systemtap_session& s)
void
be_derived_probe_group::emit_module_exit (systemtap_session& s)
{
- // if (probes.empty()) return;
+ if (probes.empty()) return;
+
sort(probes.begin(), probes.end(), be_derived_probe::comp);
for (unsigned i=0; i < probes.size (); i++)
if (! probes[i]->begin) // note polarity
@@ -368,22 +370,18 @@ struct never_builder: public derived_probe_builder
// Dwarf derived probes. "We apologize for the inconvience."
// ------------------------------------------------------------------------
-static string TOK_PROCESS("process");
static string TOK_KERNEL("kernel");
static string TOK_MODULE("module");
-
static string TOK_FUNCTION("function");
static string TOK_INLINE("inline");
+static string TOK_CALL("call");
static string TOK_RETURN("return");
static string TOK_MAXACTIVE("maxactive");
-static string TOK_CALLEES("callees");
-
static string TOK_STATEMENT("statement");
-static string TOK_LABEL("label");
-static string TOK_RELATIVE("relative");
static string TOK_ABSOLUTE("absolute");
+
struct
func_info
{
@@ -413,142 +411,6 @@ inline_instance_info
Dwarf_Die die;
};
-class
-symbol_cache
-{
- // For each module, we keep a multimap from function names to
- // (cudie, funcdie*) pairs. The first time we pass over a module,
- // we build up this multimap as an index. Our iteration over the
- // module's CUs and functions is then driven by the function or
- // statement pattern string we're scanning for.
- struct entry
- {
- Dwarf_Die cu;
- Dwarf_Die function;
- };
- typedef multimap<string, entry> index;
- map<Dwarf *, index*> indices;
- index *curr_index;
- Dwarf_Die * cu_die;
- void make_entry_for_function(Dwarf_Die *func_die);
- static int function_callback(Dwarf_Die * func, void * arg);
- void index_module(Dwarf * mod);
-public:
- void select_die_subsets(Dwarf * mod,
- string const & pattern,
- set<Dwarf_Die> & cus,
- multimap<Dwarf_Die, Dwarf_Die> & funcs);
-};
-
-void
-symbol_cache::make_entry_for_function(Dwarf_Die *func_die)
-{
- entry e;
- assert(this->cu_die);
- assert(this->curr_index);
- e.cu = *(this->cu_die);
- e.function = *(func_die);
- char const * fname = dwarf_diename(func_die);
- if (fname)
- curr_index->insert(make_pair(string(fname), e));
-}
-
-int
-symbol_cache::function_callback(Dwarf_Die * func, void * arg)
-{
- symbol_cache *sym = static_cast<symbol_cache*>(arg);
- sym->make_entry_for_function(func);
- return DWARF_CB_OK;
-}
-
-void
-symbol_cache::index_module(Dwarf *module_dwarf)
-{
- Dwarf_Off off = 0;
- size_t cuhl = 0;
- Dwarf_Off noff = 0;
- this->cu_die = NULL;
- while (dwarf_nextcu (module_dwarf, off, &noff, &cuhl, NULL, NULL, NULL) == 0)
- {
- Dwarf_Die die_mem;
- this->cu_die = dwarf_offdie (module_dwarf, off + cuhl, &die_mem);
- dwarf_getfuncs (this->cu_die, function_callback, this, 0);
- off = noff;
- }
- this->cu_die = NULL;
-}
-
-inline bool
-operator<(Dwarf_Die const & a,
- Dwarf_Die const & b)
-{
- return (a.addr < b.addr)
- || ((a.addr == b.addr) && (a.cu < b.cu))
- || ((a.addr == b.addr) && (a.cu == b.cu) && (a.abbrev < b.abbrev));
-}
-
-inline bool
-operator==(Dwarf_Die const & a,
- Dwarf_Die const & b)
-{
- return !((a < b) || (b < a));
-}
-
-void
-symbol_cache::select_die_subsets(Dwarf *mod,
- string const & pattern,
- set<Dwarf_Die> & cus,
- multimap<Dwarf_Die, Dwarf_Die> & funcs)
-{
- cus.clear();
- funcs.clear();
- index *ix = NULL;
-
- // First find the index for this module. If there's no index, build
- // one.
- map<Dwarf *, index*>::const_iterator i = indices.find(mod);
- if (i == indices.end())
- {
- this->curr_index = new index;
- index_module(mod);
- indices.insert(make_pair(mod, this->curr_index));
- ix = this->curr_index;
- this->curr_index = NULL;
- this->cu_die = NULL;
- }
- else
- ix = i->second;
-
- assert(ix);
-
- // Now stem the pattern such that we have a minimal non-wildcard
- // prefix to search in the multimap for. We will use the full pattern
- // to narrow this set further.
- string stem;
- for (string::const_iterator i = pattern.begin();
- i != pattern.end(); ++i)
- {
- if (*i == '?' || *i == '*' || *i == '[' || *i == ']')
- break;
- stem += *i;
- }
-
- // Now perform a lower-bound on the multimap, refine that result
- // set, and copy the CU and function DIEs into the parameter sets.
- index::const_iterator j = stem.empty() ? ix->begin() : ix->lower_bound(stem);
- while (j != ix->end() &&
- (stem.empty() || j->first.compare(0, stem.size(), stem) == 0))
- {
- if (fnmatch(pattern.c_str(), j->first.c_str(), 0) == 0)
- {
- cus.insert(j->second.cu);
- funcs.insert(make_pair(j->second.cu, j->second.function));
- }
- ++j;
- }
-}
-
-
static int
query_cu (Dwarf_Die * cudie, void * arg);
@@ -569,8 +431,6 @@ struct dwflpp
systemtap_session & sess;
Dwfl * dwfl;
- symbol_cache cache;
-
// These are "current" values we focus on.
Dwfl_Module * module;
Dwarf * module_dwarf;
@@ -583,9 +443,6 @@ struct dwflpp
Dwarf_Die * cu;
Dwarf_Die * function;
- set<Dwarf_Die> pattern_limited_cus;
- multimap<Dwarf_Die, Dwarf_Die> pattern_limited_funcs;
-
string module_name;
string cu_name;
string function_name;
@@ -624,14 +481,6 @@ struct dwflpp
}
}
- void limit_search_to_function_pattern(string const & pattern)
- {
- get_module_dwarf(false);
- cache.select_die_subsets(module_dwarf, pattern,
- pattern_limited_cus,
- pattern_limited_funcs);
- }
-
void focus_on_module(Dwfl_Module * m)
{
assert(m);
@@ -646,9 +495,6 @@ struct dwflpp
module_dwarf = NULL;
- pattern_limited_cus.clear();
- pattern_limited_funcs.clear();
-
cu_name.clear();
cu = NULL;
@@ -734,19 +580,28 @@ struct dwflpp
{
assert(module);
bool t = (fnmatch(pattern.c_str(), module_name.c_str(), 0) == 0);
- if (t && sess.verbose>2)
+ if (t && sess.verbose>3)
clog << "pattern '" << pattern << "' "
<< "matches "
<< "module '" << module_name << "'" << "\n";
return t;
}
+ bool module_name_final_match(string pattern)
+ {
+ // Assume module_name_matches(). Can there be any more matches?
+ // Not unless the pattern is a wildcard, since module names are
+ // presumed unique.
+ return (pattern.find('*') == string::npos &&
+ pattern.find('?') == string::npos &&
+ pattern.find('[') == string::npos);
+ }
bool function_name_matches(string pattern)
{
assert(function);
bool t = (fnmatch(pattern.c_str(), function_name.c_str(), 0) == 0);
- if (t && sess.verbose>2)
+ if (t && sess.verbose>3)
clog << "pattern '" << pattern << "' "
<< "matches "
<< "function '" << function_name << "'" << "\n";
@@ -758,7 +613,7 @@ struct dwflpp
{
assert(cu);
bool t = (fnmatch(pattern.c_str(), cu_name.c_str(), 0) == 0);
- if (t && sess.verbose>2)
+ if (t && sess.verbose>3)
clog << "pattern '" << pattern << "' "
<< "matches "
<< "CU '" << cu_name << "'" << "\n";
@@ -868,74 +723,177 @@ struct dwflpp
dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL));
}
- void cleanup () // XXX: never used
+
+
+ // -----------------------------------------------------------------
+
+ struct module_cache_entry {
+ Dwfl_Module* mod;
+ const char* name;
+ Dwarf_Addr addr;
+ };
+ typedef vector<module_cache_entry> module_cache_t;
+ module_cache_t module_cache;
+
+ static int module_caching_callback(Dwfl_Module * mod,
+ void **,
+ const char *name,
+ Dwarf_Addr addr,
+ void *param)
{
- dwfl_end (dwfl);
- dwfl = NULL;
+ module_cache_t* cache = static_cast<module_cache_t*>(param);
+ module_cache_entry it;
+ it.mod = mod;
+ it.name = name;
+ it.addr = addr;
+ cache->push_back (it);
+ return DWARF_CB_OK;
}
+
void iterate_over_modules(int (* callback)(Dwfl_Module *, void **,
const char *, Dwarf_Addr,
void *),
void * data)
{
- ptrdiff_t off = 0;
- do
+ if (module_cache.empty())
{
- off = dwfl_getmodules (dwfl, callback, data, off);
+ ptrdiff_t off = 0;
+ do
+ {
+ off = dwfl_getmodules (dwfl, module_caching_callback,
+ & module_cache, off);
+ }
+ while (off > 0);
+ dwfl_assert("dwfl_getmodules", off);
+ }
+
+ // Traverse the cache.
+ for (unsigned i = 0; i < module_cache.size(); i++)
+ {
+ module_cache_entry& it = module_cache[i];
+ int rc = callback (it.mod, 0, it.name, it.addr, data);
+ if (rc != DWARF_CB_OK) break;
}
- while (off > 0);
- dwfl_assert("dwfl_getmodules", off);
}
+
+ // -----------------------------------------------------------------
+
+ typedef map<Dwarf*, vector<Dwarf_Die>*> module_cu_cache_t;
+ module_cu_cache_t module_cu_cache;
+
void iterate_over_cus (int (*callback)(Dwarf_Die * die, void * arg),
void * data)
{
get_module_dwarf(false);
+ Dwarf *dw = module_dwarf;
+ if (!dw) return;
- if (!module_dwarf)
- return;
+ vector<Dwarf_Die>* v = module_cu_cache[dw];
+ if (v == 0)
+ {
+ v = new vector<Dwarf_Die>;
+ module_cu_cache[dw] = v;
+
+ Dwarf_Off off = 0;
+ size_t cuhl;
+ Dwarf_Off noff;
+ while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0)
+ {
+ Dwarf_Die die_mem;
+ Dwarf_Die *die;
+ die = dwarf_offdie (dw, off + cuhl, &die_mem);
+ v->push_back (*die); /* copy */
+ off = noff;
+ }
+ }
- for (set<Dwarf_Die>::const_iterator i = pattern_limited_cus.begin();
- i != pattern_limited_cus.end(); ++i)
+ for (unsigned i = 0; i < v->size(); i++)
{
- Dwarf_Die die = *i;
- if (callback (&die, data) != DWARF_CB_OK)
- break;
+ Dwarf_Die die = v->at(i);
+ int rc = (*callback)(& die, data);
+ if (rc != DWARF_CB_OK) break;
}
}
+ // -----------------------------------------------------------------
+
bool func_is_inline()
{
assert (function);
return dwarf_func_inline (function) != 0;
}
+
+ typedef map<string, vector<Dwarf_Die>*> cu_inl_function_cache_t;
+ cu_inl_function_cache_t cu_inl_function_cache;
+
+ static int cu_inl_function_caching_callback (Dwarf_Die* func, void *arg)
+ {
+ vector<Dwarf_Die>* v = static_cast<vector<Dwarf_Die>*>(arg);
+ v->push_back (* func);
+ return DWARF_CB_OK;
+ }
+
void iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void * arg),
void * data)
{
assert (function);
assert (func_is_inline ());
- dwarf_assert ("dwarf_func_inline_instances",
- dwarf_func_inline_instances (function, callback, data));
+
+ string key = module_name + ":" + cu_name + ":" + function_name;
+ vector<Dwarf_Die>* v = cu_inl_function_cache[key];
+ if (v == 0)
+ {
+ v = new vector<Dwarf_Die>;
+ cu_inl_function_cache[key] = v;
+ dwarf_func_inline_instances (function, cu_inl_function_caching_callback, v);
+ }
+
+ for (unsigned i=0; i<v->size(); i++)
+ {
+ Dwarf_Die die = v->at(i);
+ int rc = (*callback)(& die, data);
+ if (rc != DWARF_CB_OK) break;
+ }
}
+ // -----------------------------------------------------------------
+
+ typedef map<string, vector<Dwarf_Die>*> cu_function_cache_t;
+ cu_function_cache_t cu_function_cache;
+
+ static int cu_function_caching_callback (Dwarf_Die* func, void *arg)
+ {
+ vector<Dwarf_Die>* v = static_cast<vector<Dwarf_Die>*>(arg);
+ v->push_back (* func);
+ return DWARF_CB_OK;
+ }
+
void iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg),
void * data)
{
assert (module);
assert (cu);
- multimap<Dwarf_Die, Dwarf_Die>::const_iterator i = pattern_limited_funcs.lower_bound(*cu);
- while (i != pattern_limited_funcs.end() && (i->first == *cu))
+
+ string key = module_name + ":" + cu_name;
+ vector<Dwarf_Die>* v = cu_function_cache[key];
+ if (v == 0)
{
- Dwarf_Die func_die = i->second;
- if (callback (&func_die, data) != DWARF_CB_OK)
- break;
+ v = new vector<Dwarf_Die>;
+ cu_function_cache[key] = v;
+ dwarf_getfuncs (cu, cu_function_caching_callback, v, 0);
+ }
- ++i;
+ for (unsigned i=0; i<v->size(); i++)
+ {
+ Dwarf_Die die = v->at(i);
+ int rc = (*callback)(& die, data);
+ if (rc != DWARF_CB_OK) break;
}
}
@@ -1189,6 +1147,7 @@ struct dwflpp
{
assert (function);
return (dwarf_entrypc (function, addr) == 0);
+ // XXX: see also _lowpc ?
}
@@ -1199,7 +1158,8 @@ struct dwflpp
if (attr != NULL)
return (dwarf_formaddr (attr, addr) == 0);
- return ( dwarf_lowpc (die, addr) == 0);
+ return (dwarf_lowpc (die, addr) == 0);
+ // XXX: see also _entrypc ?
}
void function_die (Dwarf_Die *d)
@@ -1618,8 +1578,8 @@ struct dwflpp
Dwarf_Die *die,
Dwarf_Attribute *attr_mem,
bool lvalue,
- string & /*prelude*/,
- string & /*postlude*/,
+ string &,
+ string &,
exp_type & ty)
{
/* First boil away any qualifiers associated with the type DIE of
@@ -1923,17 +1883,15 @@ struct dwarf_derived_probe: public derived_probe
bool has_maxactive;
long maxactive_val;
+ void printsig (std::ostream &o) const;
+
void join_group (systemtap_session& s);
// Pattern registration helpers.
- static void register_relative_variants(match_node * root,
- dwarf_builder * dw);
static void register_statement_variants(match_node * root,
dwarf_builder * dw);
static void register_function_variants(match_node * root,
dwarf_builder * dw);
- static void register_inline_variants(match_node * root,
- dwarf_builder * dw);
static void register_function_and_statement_variants(match_node * root,
dwarf_builder * dw);
static void register_patterns(match_node * root);
@@ -1976,8 +1934,6 @@ struct dwarf_query
static bool get_number_param(map<string, literal *> const & params,
string const & k, Dwarf_Addr & v);
- string pt_regs_member_for_regnum(uint8_t dwarf_regnum);
-
// Result vector
vector<derived_probe *> & results;
void add_probe_point(string const & funcname,
@@ -1998,29 +1954,20 @@ struct dwarf_query
Dwarf_Addr addr);
// Extracted parameters.
- bool has_kernel;
- bool has_process;
- bool has_module;
- string process_val;
string module_val;
string function_val;
- bool has_inline_str;
bool has_function_str;
bool has_statement_str;
- bool has_inline_num;
bool has_function_num;
bool has_statement_num;
string statement_str_val;
string function_str_val;
- string inline_str_val;
Dwarf_Addr statement_num_val;
Dwarf_Addr function_num_val;
- Dwarf_Addr inline_num_val;
-
- bool has_callees;
- long callee_val;
+ bool has_call;
+ bool has_inline;
bool has_return;
bool has_maxactive;
@@ -2057,10 +2004,7 @@ struct dwarf_query
struct dwarf_builder: public derived_probe_builder
{
dwflpp *kern_dw;
- dwflpp *user_dw;
- dwarf_builder()
- : kern_dw(NULL), user_dw(NULL)
- {}
+ dwarf_builder(): kern_dw(0) {}
void build_no_more (systemtap_session &s)
{
@@ -2075,10 +2019,8 @@ struct dwarf_builder: public derived_probe_builder
~dwarf_builder()
{
- if (kern_dw)
- delete kern_dw;
- if (user_dw)
- delete user_dw;
+ // XXX: in practice, NOTREACHED
+ delete kern_dw;
}
virtual void build(systemtap_session & sess,
@@ -2142,39 +2084,33 @@ dwarf_query::dwarf_query(systemtap_session & sess,
// Reduce the query to more reasonable semantic values (booleans,
// extracted strings, numbers, etc).
- has_kernel = has_null_param(params, TOK_KERNEL);
- has_module = get_string_param(params, TOK_MODULE, module_val);
- has_process = get_string_param(params, TOK_PROCESS, process_val);
+ bool has_kernel = has_null_param(params, TOK_KERNEL);
+ if (has_kernel)
+ module_val = "kernel";
+ else
+ {
+ bool has_module = get_string_param(params, TOK_MODULE, module_val);
+ assert (has_module); // no other options are possible by construction
+ }
has_function_str = get_string_param(params, TOK_FUNCTION, function_str_val);
has_function_num = get_number_param(params, TOK_FUNCTION, function_num_val);
- has_inline_str = get_string_param(params, TOK_INLINE, inline_str_val);
- has_inline_num = get_number_param(params, TOK_INLINE, inline_num_val);
-
has_statement_str = get_string_param(params, TOK_STATEMENT, statement_str_val);
has_statement_num = get_number_param(params, TOK_STATEMENT, statement_num_val);
- callee_val = 1;
- has_callees = (has_null_param(params, TOK_CALLEES) ||
- get_number_param(params, TOK_CALLEES, callee_val));
-
+ has_call = has_null_param(params, TOK_CALL);
+ has_inline = has_null_param(params, TOK_INLINE);
has_return = has_null_param(params, TOK_RETURN);
has_maxactive = get_number_param(params, TOK_MAXACTIVE, maxactive_val);
-
- has_label = get_string_param(params, TOK_LABEL, label_val);
- has_relative = get_number_param(params, TOK_RELATIVE, relative_val);
-
has_absolute = has_null_param(params, TOK_ABSOLUTE);
if (has_function_str)
spec_type = parse_function_spec(function_str_val);
- else if (has_inline_str)
- spec_type = parse_function_spec(inline_str_val);
else if (has_statement_str)
spec_type = parse_function_spec(statement_str_val);
- build_blacklist();
+ build_blacklist(); // XXX: why not reuse amongst dwarf_query instances?
}
@@ -2309,6 +2245,7 @@ static int query_kernel_module (Dwfl_Module *, void **, const char *,
Dwarf_Addr, void *);
+// XXX: pull this into dwflpp
static bool
in_kprobes_function(systemtap_session& sess, Dwarf_Addr addr)
{
@@ -2334,6 +2271,11 @@ dwarf_query::blacklisted_p(const string& funcname,
if (section.substr(0, 6) == string(".init.") ||
section.substr(0, 6) == string(".exit."))
{
+ // 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;
@@ -2355,6 +2297,9 @@ dwarf_query::blacklisted_p(const string& funcname,
(has_return && blacklisted_return_probes.count(funcname) > 0) ||
filename == "kernel/kprobes.c" ||
0 == fnmatch ("arch/*/kernel/kprobes.c", filename.c_str(), 0))
+ // XXX: these tests (set lookup, fnmatch) could be combined into a
+ // single synthetic compiled regexp, which would allow blacklisted
+ // functions to be identified by wildcard instead of exact name.
{
if (sess.verbose>1)
clog << " skipping - blacklisted";
@@ -2465,31 +2410,36 @@ dwarf_query::add_probe_point(const string& funcname,
- // The critical determining factor when interpreting a pattern
- // string is, perhaps surprisingly: "presence of a lineno". The
- // presence of a lineno changes the search strategy completely.
- //
- // Compare the two cases:
- //
- // 1. {statement,function}(foo@file.c:lineno)
- // - find the files matching file.c
- // - in each file, find the functions matching foo
- // - query the file for line records matching lineno
- // - iterate over the line records,
- // - and iterate over the functions,
- // - if(haspc(function.DIE, line.addr))
- // - if looking for statements: probe(lineno.addr)
- // - if looking for functions: probe(function.{entrypc,return,etc.})
- //
- // 2. {statement,function}(foo@file.c)
- // - find the files matching file.c
- // - in each file, find the functions matching foo
- // - probe(function.{entrypc,return,etc.})
- //
- // Thus the first decision we make is based on the presence of a
- // lineno, and we enter entirely different sets of callbacks
- // depending on that decision.
-
+// The critical determining factor when interpreting a pattern
+// string is, perhaps surprisingly: "presence of a lineno". The
+// presence of a lineno changes the search strategy completely.
+//
+// Compare the two cases:
+//
+// 1. {statement,function}(foo@file.c:lineno)
+// - find the files matching file.c
+// - in each file, find the functions matching foo
+// - query the file for line records matching lineno
+// - iterate over the line records,
+// - and iterate over the functions,
+// - if(haspc(function.DIE, line.addr))
+// - if looking for statements: probe(lineno.addr)
+// - if looking for functions: probe(function.{entrypc,return,etc.})
+//
+// 2. {statement,function}(foo@file.c)
+// - find the files matching file.c
+// - in each file, find the functions matching foo
+// - probe(function.{entrypc,return,etc.})
+//
+// Thus the first decision we make is based on the presence of a
+// lineno, and we enter entirely different sets of callbacks
+// depending on that decision.
+//
+// Note that the first case is a generalization fo the second, in that
+// we could theoretically search through line records for matching
+// file names (a "table scan" in rdbms lingo). Luckily, file names
+// are already cached elsewhere, so we can do an "index scan" as an
+// optimization.
static void
query_statement (string const & func,
@@ -2501,11 +2451,6 @@ query_statement (string const & func,
{
try
{
- // XXX: implement
- if (q->has_relative)
- throw semantic_error("incomplete: do not know how to interpret .relative",
- q->base_probe->tok);
-
q->add_probe_point(func, file ? file : "?",
line, scope_die, stmt_addr);
}
@@ -2629,27 +2574,11 @@ query_dwarf_inline_instance (Dwarf_Die * die, void * arg)
try
{
-
- bool record_this_inline = false;
-
if (q->sess.verbose>2)
clog << "examining inline instance of " << q->dw.function_name << "\n";
- if (q->has_inline_str || q->has_statement_str)
- record_this_inline = true;
-
- else if (q->has_inline_num)
- {
- Dwarf_Addr query_addr = q->inline_num_val;
-
- if (q->has_module)
- query_addr = q->dw.module_address_to_global(query_addr);
-
- if (q->dw.die_has_pc (die, query_addr))
- record_this_inline = true;
- }
-
- if (record_this_inline)
+ if ((q->has_function_str && ! q->has_call)
+ || q->has_statement_str)
{
if (q->sess.verbose>2)
clog << "selected inline instance of " << q->dw.function_name
@@ -2683,21 +2612,12 @@ query_dwarf_func (Dwarf_Die * func, void * arg)
try
{
- // XXX: implement
- if (q->has_callees)
- throw semantic_error ("incomplete: do not know how to interpret .callees",
- q->base_probe->tok);
-
- if (q->has_label)
- throw semantic_error ("incomplete: do not know how to interpret .label",
- q->base_probe->tok);
-
q->dw.focus_on_function (func);
if (q->dw.func_is_inline ()
- && (((q->has_statement_str || q->has_inline_str)
- && q->dw.function_name_matches(q->function))
- || q->has_inline_num))
+ && (! q->has_call) && (! q->has_return)
+ && (((q->has_statement_str || q->has_function_str)
+ && q->dw.function_name_matches(q->function))))
{
if (q->sess.verbose>3)
clog << "checking instances of inline " << q->dw.function_name
@@ -2716,9 +2636,7 @@ query_dwarf_func (Dwarf_Die * func, void * arg)
else if (q->has_function_num)
{
Dwarf_Addr query_addr = q->function_num_val;
-
- if (q->has_module)
- query_addr = q->dw.module_address_to_global(query_addr);
+ query_addr = q->dw.module_address_to_global(query_addr);
Dwarf_Die d;
q->dw.function_die (&d);
@@ -2770,7 +2688,6 @@ query_cu (Dwarf_Die * cudie, void * arg)
<< "', in module '" << q->dw.module_name << "'\n";
if (q->has_statement_str
- || q->has_inline_str || q->has_inline_num
|| q->has_function_str || q->has_function_num)
{
q->filtered_srcfiles.clear();
@@ -2783,7 +2700,7 @@ query_cu (Dwarf_Die * cudie, void * arg)
// associated addresses. Unfortunately the control of this
// cannot easily be turned inside out.
- if ((q->has_statement_str || q->has_function_str || q->has_inline_str)
+ if ((q->has_statement_str || q->has_function_str)
&& (q->spec_type != function_alone))
{
// If we have a pattern string with a filename, we need
@@ -2805,7 +2722,7 @@ query_cu (Dwarf_Die * cudie, void * arg)
if (! q->filtered_functions.empty())
q->dw.resolve_prologue_endings (q->filtered_functions);
- if ((q->has_statement_str || q->has_function_str || q->has_inline_str)
+ if ((q->has_statement_str || q->has_function_str)
&& (q->spec_type == function_file_and_line))
{
// If we have a pattern string with target *line*, we
@@ -2825,7 +2742,8 @@ query_cu (Dwarf_Die * cudie, void * arg)
query_func_info (i->first, i->second, q);
// Or all inline instances (if we're scanning inlines)
- if (q->has_statement_str || q->has_inline_str || q->has_inline_num)
+ if (q->has_statement_str
+ || ((q->has_function_str || q->has_function_num) && !q->has_call))
for (map<Dwarf_Addr, inline_instance_info>::iterator i
= q->filtered_inlines.begin(); i != q->filtered_inlines.end(); ++i)
query_inline_instance_info (i->first, i->second, q);
@@ -2839,8 +2757,7 @@ query_cu (Dwarf_Die * cudie, void * arg)
assert (q->has_statement_num);
Dwarf_Addr query_addr = q->statement_num_val;
- if (q->has_module)
- query_addr = q->dw.module_address_to_global(query_addr);
+ query_addr = q->dw.module_address_to_global(query_addr);
query_statement ("", "", -1, NULL, query_addr, q);
}
@@ -2856,9 +2773,9 @@ query_cu (Dwarf_Die * cudie, void * arg)
static int
query_kernel_module (Dwfl_Module *mod,
- void **userdata __attribute__ ((unused)),
+ void **,
const char *name,
- Dwarf_Addr base __attribute__ ((unused)),
+ Dwarf_Addr,
void *arg)
{
if (TOK_KERNEL == name)
@@ -2873,10 +2790,11 @@ query_kernel_module (Dwfl_Module *mod,
static int
-query_module (Dwfl_Module *mod __attribute__ ((unused)),
- void **userdata __attribute__ ((unused)),
- const char *name, Dwarf_Addr,
- void *arg __attribute__ ((unused)))
+query_module (Dwfl_Module *mod,
+ void **,
+ const char *name,
+ Dwarf_Addr,
+ void *arg)
{
dwarf_query * q = static_cast<dwarf_query *>(arg);
@@ -2886,17 +2804,13 @@ query_module (Dwfl_Module *mod __attribute__ ((unused)),
// If we have enough information in the pattern to skip a module and
// the module does not match that information, return early.
-
- if (q->has_kernel && !q->dw.module_name_matches(TOK_KERNEL))
- return DWARF_CB_OK;
-
- if (q->has_module && !q->dw.module_name_matches(q->module_val))
+ if (!q->dw.module_name_matches(q->module_val))
return DWARF_CB_OK;
// Validate the machine code in this elf file against the
// session machine. This is important, in case the wrong kind
// of debuginfo is being automagically processed by elfutils.
- // Unfortunately, while we can tell i686 apart from x86-64,
+ // While we can tell i686 apart from x86-64, unfortunately
// we can't help confusing i586 vs i686 (both EM_386).
Dwarf_Addr _junk;
@@ -2911,9 +2825,10 @@ query_module (Dwfl_Module *mod __attribute__ ((unused)),
& debug_filename);
const string& sess_machine = q->sess.architecture;
string expect_machine;
+
switch (elf_machine)
{
- case EM_386: expect_machine = "i686"; break;
+ case EM_386: expect_machine = "i?86"; break; // accept e.g. i586
case EM_X86_64: expect_machine = "x86_64"; break;
case EM_PPC: expect_machine = "ppc"; break;
case EM_PPC64: expect_machine = "ppc64"; break;
@@ -2926,7 +2841,7 @@ query_module (Dwfl_Module *mod __attribute__ ((unused)),
if (! debug_filename) debug_filename = main_filename;
if (! debug_filename) debug_filename = name;
- if (sess_machine != expect_machine)
+ if (fnmatch (expect_machine.c_str(), sess_machine.c_str(), 0) != 0)
{
stringstream msg;
msg << "ELF machine " << expect_machine << " (code " << elf_machine
@@ -2945,7 +2860,7 @@ query_module (Dwfl_Module *mod __attribute__ ((unused)),
<< " (code " << elf_machine << ")"
<< "\n";
- if (q->has_inline_num || q->has_function_num || q->has_statement_num)
+ if (q->has_function_num || q->has_statement_num)
{
// If we have module("foo").function(0xbeef) or
// module("foo").statement(0xbeef), the address is relative
@@ -2955,17 +2870,11 @@ query_module (Dwfl_Module *mod __attribute__ ((unused)),
Dwarf_Addr addr;
if (q->has_function_num)
addr = q->function_num_val;
- else if (q->has_inline_num)
- addr = q->inline_num_val;
else
addr = q->statement_num_val;
-
- // NB: We should not have kernel.* here; global addresses
- // should have bypassed query_module in dwarf_builder::build
- // and gone directly to query_cu.
-
- assert (!q->has_kernel);
- assert (q->has_module);
+
+ // NB: we don't need to add the module base address or bias
+ // value here (for reasons that may be coincidental).
q->dw.query_cu_containing_module_address(addr, q);
}
else
@@ -2973,21 +2882,15 @@ query_module (Dwfl_Module *mod __attribute__ ((unused)),
// Otherwise if we have a function("foo") or statement("foo")
// specifier, we have to scan over all the CUs looking for
// the function(s) in question
-
- q->dw.limit_search_to_function_pattern(q->function);
-
- assert(q->has_function_str || q->has_inline_str || q->has_statement_str);
+ assert(q->has_function_str || q->has_statement_str);
q->dw.iterate_over_cus(&query_cu, q);
-
- // If we just processed the module "kernel", and the user asked for
- // the kernel pattern, there's no need to iterate over any further
- // modules
-
- if (q->has_kernel && q->dw.module_name_matches(TOK_KERNEL))
- return DWARF_CB_ABORT;
}
- return DWARF_CB_OK;
+ // If we know that there will be no more matches, abort early.
+ if (q->dw.module_name_final_match(q->module_val))
+ return DWARF_CB_ABORT;
+ else
+ return DWARF_CB_OK;
}
catch (const semantic_error& e)
{
@@ -3463,6 +3366,20 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
void
+dwarf_derived_probe::printsig (ostream& o) const
+{
+ // Instead of just printing the plain locations, we add a PC value
+ // as a comment as a way of telling e.g. apart multiple inlined
+ // function instances. This is distinct from the verbose/clog
+ // output, since this part goes into the cache hash calculations.
+ sole_location()->print (o);
+ o << " /* pc=0x" << hex << addr << dec << " */";
+ printsig_nested (o);
+}
+
+
+
+void
dwarf_derived_probe::join_group (systemtap_session& s)
{
if (! s.dwarf_derived_probes)
@@ -3538,12 +3455,10 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname,
string fn_or_stmt;
if (q.has_function_str || q.has_function_num)
fn_or_stmt = "function";
- else if (q.has_inline_str || q.has_inline_num)
- fn_or_stmt = "inline";
else
fn_or_stmt = "statement";
- if (q.has_function_str || q.has_inline_str || q.has_statement_str)
+ if (q.has_function_str || q.has_statement_str)
{
string retro_name = funcname;
if (filename != "")
@@ -3554,13 +3469,11 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname,
(new probe_point::component
(fn_or_stmt, new literal_string (retro_name)));
}
- else if (q.has_function_num || q.has_inline_num || q.has_statement_num)
+ else if (q.has_function_num || q.has_statement_num)
{
Dwarf_Addr retro_addr;
if (q.has_function_num)
retro_addr = q.function_num_val;
- else if (q.has_inline_num)
- retro_addr = q.inline_num_val;
else
retro_addr = q.statement_num_val;
comps.push_back (new probe_point::component
@@ -3571,83 +3484,36 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname,
comps.push_back (new probe_point::component (TOK_ABSOLUTE));
}
+ if (q.has_call)
+ comps.push_back (new probe_point::component(TOK_CALL));
+ if (q.has_inline)
+ comps.push_back (new probe_point::component(TOK_INLINE));
if (has_return)
- {
- comps.push_back (new probe_point::component(TOK_RETURN));
- if (has_maxactive)
- comps.push_back (new probe_point::component
- (TOK_MAXACTIVE, new literal_number(maxactive_val)));
- }
+ comps.push_back (new probe_point::component(TOK_RETURN));
+ if (has_maxactive)
+ comps.push_back (new probe_point::component
+ (TOK_MAXACTIVE, new literal_number(maxactive_val)));
locations.push_back(new probe_point(comps, q.base_loc->tok));
}
void
-dwarf_derived_probe::register_relative_variants(match_node * root,
- dwarf_builder * dw)
-{
- // Here we match 2 forms:
- //
- // .
- // .relative(NN)
-
- root->bind(dw);
- root->bind_num(TOK_RELATIVE)->bind(dw);
-}
-
-void
dwarf_derived_probe::register_statement_variants(match_node * root,
dwarf_builder * dw)
{
- // Here we match 3 forms:
- //
- // .
- // .return
- // .label("foo")
-
- register_relative_variants(root, dw);
- register_relative_variants(root->bind_str(TOK_LABEL), dw);
-}
-
-void
-dwarf_derived_probe::register_inline_variants(match_node * root,
- dwarf_builder * dw)
-{
- // Here we match 4 forms:
- //
- // .
- // .callees
- // .callees(N)
- //
- // The last form permits N-level callee resolving without any
- // recursive .callees.callees.callees... pattern-matching on our part.
-
root->bind(dw);
- root->bind(TOK_CALLEES)->bind(dw);
- root->bind_num(TOK_CALLEES)->bind(dw);
}
void
dwarf_derived_probe::register_function_variants(match_node * root,
dwarf_builder * dw)
{
- // Here we match 5 forms:
- //
- // .
- // .return
- // .return.maxactive(N)
- // .callees
- // .callees(N)
- //
- // The last form permits N-level callee resolving without any
- // recursive .callees.callees.callees... pattern-matching on our part.
-
root->bind(dw);
+ root->bind(TOK_INLINE)->bind(dw);
+ root->bind(TOK_CALL)->bind(dw);
root->bind(TOK_RETURN)->bind(dw);
root->bind(TOK_RETURN)->bind_num(TOK_MAXACTIVE)->bind(dw);
- root->bind(TOK_CALLEES)->bind(dw);
- root->bind_num(TOK_CALLEES)->bind(dw);
}
void
@@ -3658,15 +3524,11 @@ dwarf_derived_probe::register_function_and_statement_variants(match_node * root,
//
// .function("foo")
// .function(0xdeadbeef)
- // .inline("foo")
- // .inline(0xdeadbeef)
// .statement("foo")
// .statement(0xdeadbeef)
register_function_variants(root->bind_str(TOK_FUNCTION), dw);
register_function_variants(root->bind_num(TOK_FUNCTION), dw);
- register_inline_variants(root->bind_str(TOK_INLINE), dw);
- register_inline_variants(root->bind_num(TOK_INLINE), dw);
register_statement_variants(root->bind_str(TOK_STATEMENT), dw);
register_statement_variants(root->bind_num(TOK_STATEMENT), dw);
}
@@ -3676,12 +3538,6 @@ dwarf_derived_probe::register_patterns(match_node * root)
{
dwarf_builder *dw = new dwarf_builder();
- // Here we match 3 forms:
- //
- // .kernel
- // .module("foo")
- // .process("foo")
-
register_function_and_statement_variants(root->bind(TOK_KERNEL), dw);
register_function_and_statement_variants(root->bind_str(TOK_MODULE), dw);
root->bind(TOK_KERNEL)->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)->bind(dw);
@@ -3696,6 +3552,10 @@ void
dwarf_derived_probe_group::enroll (dwarf_derived_probe* p)
{
probes_by_module.insert (make_pair (p->module, p));
+
+ // XXX: probes put at the same address should all share a
+ // single kprobe/kretprobe, and have their handlers executed
+ // sequentially.
}
@@ -3866,57 +3726,37 @@ dwarf_builder::build(systemtap_session & sess,
std::map<std::string, literal *> const & parameters,
vector<derived_probe *> & finished_results)
{
- dwflpp *dw = NULL;
-
- string dummy;
- bool has_kernel = dwarf_query::has_null_param(parameters, TOK_KERNEL);
- bool has_module = dwarf_query::get_string_param(parameters, TOK_MODULE, dummy);
-
// NB: the kernel/user dwlfpp objects are long-lived.
// XXX: but they should be per-session, as this builder object
// may be reused if we try to cross-instrument multiple targets.
- if (has_kernel || has_module)
- {
- if (!kern_dw)
- {
- kern_dw = new dwflpp(sess);
- assert(kern_dw);
- kern_dw->setup(true);
- }
- dw = kern_dw;
+ if (!kern_dw)
+ {
+ kern_dw = new dwflpp(sess);
+ assert(kern_dw);
+ kern_dw->setup(true);
+ }
- Dwfl_Module* km = 0;
- dw->iterate_over_modules(&query_kernel_module, &km);
- if (km)
+ Dwfl_Module* km = 0;
+ kern_dw->iterate_over_modules(&query_kernel_module, &km);
+ if (km)
+ {
+ sess.sym_kprobes_text_start = lookup_symbol_address (km, "__kprobes_text_start");
+ sess.sym_kprobes_text_end = lookup_symbol_address (km, "__kprobes_text_end");
+ sess.sym_stext = lookup_symbol_address (km, "_stext");
+
+ if (sess.verbose > 2)
{
- sess.sym_kprobes_text_start = lookup_symbol_address (km, "__kprobes_text_start");
- sess.sym_kprobes_text_end = lookup_symbol_address (km, "__kprobes_text_end");
- sess.sym_stext = lookup_symbol_address (km, "_stext");
-
- if (sess.verbose > 2)
- {
- clog << "control symbols:"
- // abbreviate the names - they're for our debugging only anyway
- << " kts: 0x" << hex << sess.sym_kprobes_text_start
- << " kte: 0x" << sess.sym_kprobes_text_end
- << " stext: 0x" << sess.sym_stext
- << dec << endl;
- }
+ clog << "control symbols:"
+ // abbreviate the names - they're for our debugging only anyway
+ << " kts: 0x" << hex << sess.sym_kprobes_text_start
+ << " kte: 0x" << sess.sym_kprobes_text_end
+ << " stext: 0x" << sess.sym_stext
+ << dec << endl;
}
}
- else
- {
- if (!user_dw)
- {
- user_dw = new dwflpp(sess);
- assert(user_dw);
- user_dw->setup(false);
- }
- dw = user_dw;
- }
- assert(dw);
+ dwflpp* dw = kern_dw;
dwarf_query q(sess, base, location, *dw, parameters, finished_results);
if (q.has_absolute)
@@ -3930,43 +3770,15 @@ dwarf_builder::build(systemtap_session & sess,
// For kernel.statement(NUM).absolute probe points, we bypass
// all the debuginfo stuff: We just wire up a
// dwarf_derived_probe right here and now.
- dwarf_derived_probe* p = new dwarf_derived_probe ("", "", 0, "kernel", "",
- q.statement_num_val, q.statement_num_val,
- q, 0);
+ dwarf_derived_probe* p =
+ new dwarf_derived_probe ("", "", 0, "kernel", "",
+ q.statement_num_val, q.statement_num_val,
+ q, 0);
finished_results.push_back (p);
return;
}
-
- if (q.has_kernel &&
- (q.has_function_num || q.has_inline_num || q.has_statement_num))
- {
- // If we have kernel.function(0xbeef), or
- // kernel.statement(0xbeef) the address is global (relative to
- // the kernel) and we can seek directly to the module and cudie
- // in question.
- Dwarf_Addr a;
- if (q.has_function_num)
- a = q.function_num_val;
- else if (q.has_inline_num)
- a = q.inline_num_val;
- else
- a = q.statement_num_val;
- dw->focus_on_module_containing_global_address(a);
- dw->query_cu_containing_global_address(a, &q);
- }
- else
- {
- // Otherwise we have module("*bar*"), kernel.statement("foo"), or
- // kernel.function("foo"); in these cases we need to scan all
- // the modules.
- assert((q.has_kernel && q.has_function_str) ||
- (q.has_kernel && q.has_inline_str) ||
- (q.has_kernel && q.has_statement_str) ||
- (q.has_module));
-
- dw->iterate_over_modules(&query_module, &q);
- }
+ dw->iterate_over_modules(&query_module, &q);
}
diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog
index 50829210..00c99ec5 100644
--- a/testsuite/ChangeLog
+++ b/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2007-03-30 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 1570
+ * */*.stp: Adapt to .inline -> .function change.
+ * lib/stap_run.exp, stap_run2.exp, stap_run_binary.exp: Shorten
+ pass/fail dejagnu log lines.
+ * systemtap.syscall/sys.stp, test.tcl: Make slightly more
+ compatible and failure more verbose.
+
2007-03-29 Frank Ch. Eigler <fche@elastic.org>
* systemtap.maps/ix_*.exp: Add catch around close.
diff --git a/testsuite/buildok/six.stp b/testsuite/buildok/six.stp
index 2d9a40aa..a4a893da 100755
--- a/testsuite/buildok/six.stp
+++ b/testsuite/buildok/six.stp
@@ -4,7 +4,7 @@
# listed in PR 1155 we cannot resolve the parameters of the inline
# at the moment.
-probe kernel.inline("context_switch")? {
+probe kernel.function("context_switch").inline ? {
log ("found an inline function")
}
diff --git a/testsuite/lib/stap_run.exp b/testsuite/lib/stap_run.exp
index 68fceb32..baf41d9b 100644
--- a/testsuite/lib/stap_run.exp
+++ b/testsuite/lib/stap_run.exp
@@ -1,9 +1,3 @@
-# stap_run.exp
-#
-# Will Cohen
-# 8/12/2005
-
-
# stap_run TEST_NAME LOAD_GEN_FUNCTION OUTPUT_CHECK_STRING
# TEST_NAME is path to the current test
# LOAD_GEN_FUNCTION (optional) to produce something to measure
@@ -21,6 +15,10 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args }
global probe_errors
global skipped_probes
+ # zap the srcdir prefix
+ set test_file_name $TEST_NAME
+ set TEST_NAME [regsub {.*/testsuite/} $TEST_NAME ""]
+
# initialize probe_errors and skipped_probes to 0
set probe_errors 0
set skipped_probes 0
@@ -28,8 +26,8 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args }
if {[info procs installtest_p] != "" && ![installtest_p]} { untested $TEST_NAME; return }
set cmd [concat {stap -v} $args]
- if [file readable $TEST_NAME] {
- lappend cmd $TEST_NAME
+ if [file readable $test_file_name] {
+ lappend cmd $test_file_name
}
eval spawn $cmd
expect {
diff --git a/testsuite/lib/stap_run2.exp b/testsuite/lib/stap_run2.exp
index d65e3874..290f0d84 100644
--- a/testsuite/lib/stap_run2.exp
+++ b/testsuite/lib/stap_run2.exp
@@ -11,6 +11,10 @@
set timeout 20
proc stap_run2 { TEST_NAME args } {
+ # zap the srcdir prefix
+ set test_file_name $TEST_NAME
+ set TEST_NAME [regsub {.*/testsuite/} $TEST_NAME ""]
+
if {[info procs installtest_p] != "" && ![installtest_p]} { untested $TEST_NAME; return }
# fix up expected string
@@ -18,8 +22,8 @@ proc stap_run2 { TEST_NAME args } {
# spawn test
set cmd [concat {stap -v} $args]
- if [file readable $TEST_NAME] {
- lappend cmd $TEST_NAME
+ if [file readable $test_file_name] {
+ lappend cmd $test_file_name
}
eval spawn $cmd
@@ -30,7 +34,7 @@ proc stap_run2 { TEST_NAME args } {
{set pass$expect_out(1,string) "\t0\t0\t0"; exp_continue}
-re {^Pass 5: starting run.\r\n} {exp_continue}
-ex $output {
- pass "$TEST_NAME passed"
+ pass "$TEST_NAME"
expect {
-re {^Pass\ ([5]):[^\r]*\ in\ ([0-9]+)usr/([0-9]+)sys/([0-9]+)real\ ms.\r\n}
{set pass$expect_out(1,string) "\t$expect_out(2,string)\t$expect_out(3,string)\t$expect_out(4,string)"
diff --git a/testsuite/lib/stap_run_binary.exp b/testsuite/lib/stap_run_binary.exp
index f29e8f35..1d31d817 100644
--- a/testsuite/lib/stap_run_binary.exp
+++ b/testsuite/lib/stap_run_binary.exp
@@ -6,15 +6,19 @@
# global result_string must be set to the expected output
proc stap_run_binary { TEST_NAME} {
+ # zap the srcdir prefix
+ set test_file_name $TEST_NAME
+ set TEST_NAME [regsub {.*/testsuite/} $TEST_NAME ""]
+
if {[info procs installtest_p] != "" && ![installtest_p]} {untested $TEST_NAME; return}
set hex_args {-ve 8/1 "%02x " "\n"}
- set res [exec stap $TEST_NAME | hexdump $hex_args]
+ set res [exec stap $test_file_name | hexdump $hex_args]
if {[string compare $res $::result_string] == 0} {
- pass "$TEST_NAME passed"
+ pass "$TEST_NAME"
} else {
- fail "$TEST_NAME failed"
+ fail "$TEST_NAME"
puts "EXPECTED:\n-----------------------\n<$::result_string>"
puts "-----------------------\n"
puts "GOT:\n-----------------------\n<$res>"
diff --git a/testsuite/semko/twentytwo.stp b/testsuite/semko/twentytwo.stp
index 3d2f6429..9321d5f6 100755
--- a/testsuite/semko/twentytwo.stp
+++ b/testsuite/semko/twentytwo.stp
@@ -3,6 +3,6 @@
# tests that a non-inline function is *not* matched using
# the inline() pattern
-probe kernel.inline("sys_recv") {
+probe kernel.function("sys_recv").inline {
log ("found a non-inline via inline()")
}
diff --git a/testsuite/semok/twenty.stp b/testsuite/semok/twenty.stp
index 6d7f5183..2e85c5e6 100755
--- a/testsuite/semok/twenty.stp
+++ b/testsuite/semok/twenty.stp
@@ -2,7 +2,9 @@
probe kernel.function("*") {}
probe module("*").function("*") {}
+probe kernel.function("*").call {}
+probe module("*").function("*").call {}
probe kernel.function("*").return {}
probe module("*").function("*").return {}
-probe kernel.inline("*") {}
-probe module("*").inline("*") {}
+probe kernel.function("*").inline {}
+probe module("*").function("*").inline {}
diff --git a/testsuite/systemtap.base/probefunc.exp b/testsuite/systemtap.base/probefunc.exp
index e131fafb..fbb45534 100644
--- a/testsuite/systemtap.base/probefunc.exp
+++ b/testsuite/systemtap.base/probefunc.exp
@@ -49,8 +49,8 @@ set probepoint "kernel.function(\"scheduler_tick\")"
set script [format $systemtap_script $probepoint]
stap_run $prefix$probepoint sleep_one_sec $output_string -e $script
-# test probefunc() with kernel.inline()
+# test probefunc() with kernel.function().inline
set output_string "\\mcontext_switch\\M\r\n"
-set probepoint "kernel.inline(\"context_switch\")"
+set probepoint "kernel.function(\"context_switch\").inline"
set script [format $systemtap_script $probepoint]
stap_run $prefix$probepoint sleep_one_sec $output_string -e $script
diff --git a/testsuite/systemtap.stress/all_kernel_functions.exp b/testsuite/systemtap.stress/all_kernel_functions.exp
index f54f53e1..6dded726 100644
--- a/testsuite/systemtap.stress/all_kernel_functions.exp
+++ b/testsuite/systemtap.stress/all_kernel_functions.exp
@@ -17,7 +17,7 @@ proc genload {} {
proc probe_ok {probepoint} {
set cmd {exec stap -p2 -e}
lappend cmd "probe $probepoint {}"
- return ![catch $cmd]
+ return [expr ![catch $cmd]]
}
set systemtap_script {
@@ -25,12 +25,10 @@ set systemtap_script {
probe %s {
stat[probefunc()] <<< 1
}
- probe begin {
- log("systemtap starting probe")
- }
+ probe begin { log ("systemtap starting probe") }
probe end {
- log("systemtap ending probe")
- foreach (func in stat)
+ log ("systemtap ending probe")
+ foreach (func in stat limit 5) # don't overflow expect buffer
printf("%%d %%s\n", @count(stat[func]), func)
}
}
diff --git a/testsuite/systemtap.stress/whitelist.exp b/testsuite/systemtap.stress/whitelist.exp
index 75f0df8a..fda33a7c 100644
--- a/testsuite/systemtap.stress/whitelist.exp
+++ b/testsuite/systemtap.stress/whitelist.exp
@@ -223,7 +223,6 @@ proc init_probes_all {} {
global init_probes_all_script
catch {exec stap -p2 -e $init_probes_all_script > /tmp/whitelist_tmpfile}
catch {exec grep "^kernel.function" /tmp/whitelist_tmpfile > $PROBES_ALL }
- catch {exec grep "^kernel.inline" /tmp/whitelist_tmpfile >> $PROBES_ALL }
catch {exec rm -f /tmp/whitelist_tmpfile}
if {[get_linesize $PROBES_ALL] == 0} {
return 1
diff --git a/testsuite/systemtap.syscall/sys.stp b/testsuite/systemtap.syscall/sys.stp
index ab822ebb..e3564a15 100755
--- a/testsuite/systemtap.syscall/sys.stp
+++ b/testsuite/systemtap.syscall/sys.stp
@@ -11,7 +11,7 @@ probe begin {
}
-probe syscall.* {
+probe syscall.* ? {
if (pid() == target()) {
if (entry) printf("\n")
printf("%s%s: %s (%s) = ", indent_str[indent], execname(), name, argstr)
@@ -21,7 +21,7 @@ probe syscall.* {
}
}
-probe syscall.*.return {
+probe syscall.*.return ? {
if (pid() == target()) {
if (indent) indent--
if (entry)
diff --git a/testsuite/systemtap.syscall/test.tcl b/testsuite/systemtap.syscall/test.tcl
index 082eaabe..8c228cba 100755
--- a/testsuite/systemtap.syscall/test.tcl
+++ b/testsuite/systemtap.syscall/test.tcl
@@ -86,7 +86,10 @@ foreach line [split $output "\n"] {
if {$i >= $ind} {
puts "PASS"
} else {
- puts "$testname FAILED"
+ puts "$testname FAILED. output of \"$cmd\" was:"
+ puts "------------------------------------------"
+ puts $output
+ puts "------------------------------------------"
puts "RESULTS: (\'*\' = MATCHED EXPECTED)"
set i 0
foreach line [split $output "\n"] {