summaryrefslogtreecommitdiffstats
path: root/tapsets.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'tapsets.cxx')
-rw-r--r--tapsets.cxx1041
1 files changed, 663 insertions, 378 deletions
diff --git a/tapsets.cxx b/tapsets.cxx
index 54b951cd..a45233fc 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -14,6 +14,7 @@
#include "translate.h"
#include "session.h"
#include "util.h"
+#include "dwarf_wrappers.h"
#include <cstdlib>
#include <algorithm>
@@ -61,7 +62,6 @@ extern "C" {
using namespace std;
using namespace __gnu_cxx;
-
// ------------------------------------------------------------------------
// Generic derived_probe_group: contains an ordinary vector of the
// given type. It provides only the enrollment function.
@@ -81,6 +81,10 @@ public:
// begin/end/error probes are run right during registration / deregistration
// ------------------------------------------------------------------------
+static string TOK_BEGIN("begin");
+static string TOK_END("end");
+static string TOK_ERROR("error");
+
enum be_t { BEGIN, END, ERROR };
struct be_derived_probe: public derived_probe
@@ -116,7 +120,6 @@ public:
void emit_module_exit (systemtap_session& s);
};
-
struct be_builder: public derived_probe_builder
{
be_t type;
@@ -126,13 +129,13 @@ struct be_builder: public derived_probe_builder
virtual void build(systemtap_session &,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results)
{
int64_t priority;
- if ((type == BEGIN && !get_param(parameters, "begin", priority)) ||
- (type == END && !get_param(parameters, "end", priority)) ||
- (type == ERROR && !get_param(parameters, "error", priority)))
+ if ((type == BEGIN && !get_param(parameters, TOK_BEGIN, priority)) ||
+ (type == END && !get_param(parameters, TOK_END, priority)) ||
+ (type == ERROR && !get_param(parameters, TOK_ERROR, priority)))
priority = 0;
finished_results.push_back(
new be_derived_probe(base, location, type, priority));
@@ -414,6 +417,8 @@ be_derived_probe_group::emit_module_exit (systemtap_session& s)
// never probes are never run
// ------------------------------------------------------------------------
+static string TOK_NEVER("never");
+
struct never_derived_probe: public derived_probe
{
never_derived_probe (probe* p): derived_probe (p) {}
@@ -428,7 +433,7 @@ struct never_builder: public derived_probe_builder
virtual void build(systemtap_session &,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const &,
+ literal_map_t const &,
vector<derived_probe *> & finished_results)
{
finished_results.push_back(new never_derived_probe(base, location));
@@ -472,7 +477,7 @@ struct
func_info
{
func_info()
- : decl_file(NULL), decl_line(-1), addr(0), prologue_end(0)
+ : decl_file(NULL), decl_line(-1), addr(0), prologue_end(0), weak(false)
{
memset(&die, 0, sizeof(die));
}
@@ -482,6 +487,7 @@ func_info
Dwarf_Die die;
Dwarf_Addr addr;
Dwarf_Addr prologue_end;
+ bool weak;
};
struct
@@ -503,6 +509,7 @@ struct dwarf_query; // forward decls
struct dwflpp;
struct symbol_table;
+
struct
module_info
{
@@ -559,13 +566,20 @@ symbol_table
module_info *mod_info; // associated module
map<string, func_info*> map_by_name;
vector<func_info*> list_by_addr;
+#ifdef __powerpc__
+ GElf_Word opd_section;
+#endif
- void add_symbol(const char *name, Dwarf_Addr addr, Dwarf_Addr *high_addr);
+ void add_symbol(const char *name, bool weak, Dwarf_Addr addr,
+ Dwarf_Addr *high_addr);
enum info_status read_symbols(FILE *f, const string& path);
enum info_status read_from_elf_file(const string& path);
enum info_status read_from_text_file(const string& path);
enum info_status get_from_elf();
+ void prepare_section_rejection(Dwfl_Module *mod);
+ bool reject_section(GElf_Word section);
void mark_dwarf_redundancies(dwflpp *dw);
+ void purge_syscall_stubs();
func_info *lookup_symbol(const string& name);
Dwarf_Addr lookup_symbol_address(const string& name);
func_info *get_func_containing_address(Dwarf_Addr addr);
@@ -595,6 +609,8 @@ dwarf_diename_integrate (Dwarf_Die *die)
return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem));
}
+enum line_t { ABSOLUTE, RELATIVE, RANGE, WILDCARD };
+
struct dwflpp
{
systemtap_session & sess;
@@ -816,35 +832,6 @@ struct dwflpp
return t;
}
-
- // NB: "rc == 0" means OK in this case
- static void dwfl_assert(string desc, int rc, string extra_msg = "")
- {
- string msg = "libdwfl failure (" + desc + "): ";
- if (rc < 0) msg += dwfl_errmsg (rc);
- else if (rc > 0) msg += strerror (rc);
- if (rc != 0)
- {
- if (extra_msg.length() > 0)
- msg += "\n" + extra_msg;
- throw semantic_error (msg);
- }
- }
-
- void dwarf_assert(string desc, int rc) // NB: "rc == 0" means OK in this case
- {
- string msg = "libdw failure (" + desc + "): ";
- if (rc < 0) msg += dwarf_errmsg (rc);
- else if (rc > 0) msg += strerror (rc);
- if (rc != 0)
- throw semantic_error (msg);
- }
-
- // static so pathname_caching_callback() can access them
- static module_cache_t module_cache;
- static bool ignore_vmlinux;
-
-
dwflpp(systemtap_session & session)
:
sess(session),
@@ -858,7 +845,6 @@ struct dwflpp
cu(NULL),
function(NULL)
{
- ignore_vmlinux = sess.ignore_vmlinux;
}
// Called by dwfl_linux_kernel_report_offline(). We may not have
@@ -867,12 +853,16 @@ struct dwflpp
// (Currently, we get all the elf info we need via elfutils -- if the
// elf file exists -- so remembering the pathname isn't strictly needed.
// But we still need to handle the case where there's no vmlinux.)
+
+ static systemtap_session* this_session; // XXX: used only due to elfutils shortcoming
+
static int pathname_caching_callback(const char *name, const char *path)
{
module_info *mi = new module_info(name);
- module_cache.cache[name] = mi;
+ assert (this_session);
+ this_session->module_cache->cache[name] = mi;
- if (ignore_vmlinux && path && name == TOK_KERNEL)
+ if (this_session->ignore_vmlinux && path && name == TOK_KERNEL)
{
// report_kernel() in elfutils found vmlinux, but pretend it didn't.
// Given a non-null path, returning 1 means keep reporting modules.
@@ -894,12 +884,17 @@ struct dwflpp
void setup(bool kernel, bool debuginfo_needed = true)
{
+ if (! sess.module_cache)
+ sess.module_cache = new module_cache ();
+
// XXX: this is where the session -R parameter could come in
static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug:build";
static char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH");
static char *debuginfo_path = (debuginfo_env_arr ?
debuginfo_env_arr : debuginfo_path_arr);
+ static const char *debug_path = (debuginfo_env_arr ?
+ debuginfo_env_arr : sess.kernel_release.c_str());
static const Dwfl_Callbacks proc_callbacks =
{
@@ -925,17 +920,24 @@ struct dwflpp
dwfl_report_begin (dwfl);
int (*callback)(const char *name, const char *path);
- if (sess.consult_symtab && !module_cache.paths_collected)
+ if (sess.consult_symtab && !sess.module_cache->paths_collected)
{
callback = pathname_caching_callback;
- module_cache.paths_collected = true;
+ sess.module_cache->paths_collected = true;
}
else
callback = NULL;
+
+ // XXX: we should not need to set this static variable just
+ // for the callback. The following elfutils routine should
+ // take some void* parameter to pass context to the callback.
+ this_session = & sess;
int rc = dwfl_linux_kernel_report_offline (dwfl,
- sess.kernel_release.c_str(),
+ debug_path,
/* selection predicate */
callback);
+ this_session = 0;
+
if (debuginfo_needed)
dwfl_assert (string("missing kernel ") +
sess.kernel_release +
@@ -983,10 +985,13 @@ struct dwflpp
Dwarf_Addr addr,
void *param)
{
- module_cache_t *cache = static_cast<module_cache_t*>(param);
+ systemtap_session *sess = static_cast<systemtap_session*>(param);
+ module_cache_t *cache = sess->module_cache;
module_info *mi = NULL;
- if (ignore_vmlinux && name == TOK_KERNEL)
+ assert (cache);
+
+ if (sess->ignore_vmlinux && name == TOK_KERNEL)
// This wouldn't be called for vmlinux if vmlinux weren't there.
return DWARF_CB_OK;
@@ -1004,18 +1009,18 @@ struct dwflpp
void cache_modules_dwarf()
{
- if (!module_cache.dwarf_collected)
+ if (!sess.module_cache->dwarf_collected)
{
ptrdiff_t off = 0;
do
{
if (pending_interrupts) return;
off = dwfl_getmodules (dwfl, module_caching_callback,
- & module_cache, off);
+ & sess, off);
}
while (off > 0);
- dwfl_assert("dwfl_getmodules", off);
- module_cache.dwarf_collected = true;
+ dwfl_assert("dwfl_getmodules", off == 0);
+ sess.module_cache->dwarf_collected = true;
}
}
@@ -1027,7 +1032,7 @@ struct dwflpp
cache_modules_dwarf();
map<string, module_info*>::iterator i;
- for (i = module_cache.cache.begin(); i != module_cache.cache.end(); i++)
+ for (i = sess.module_cache->cache.begin(); i != sess.module_cache->cache.end(); i++)
{
if (pending_interrupts) return;
module_info *mi = i->second;
@@ -1143,105 +1148,121 @@ struct dwflpp
bool has_single_line_record (dwarf_query * q, char const * srcfile, int lineno);
void iterate_over_srcfile_lines (char const * srcfile,
- int lineno,
+ int lines[2],
bool need_single_match,
- void (* callback) (Dwarf_Line * line, void * arg),
+ enum line_t line_type,
+ void (* callback) (const dwarf_line_t& line,
+ void * arg),
void *data)
{
Dwarf_Line **srcsp = NULL;
size_t nsrcs = 0;
dwarf_query * q = static_cast<dwarf_query *>(data);
+ int lineno = lines[0];
get_module_dwarf();
- dwarf_assert ("dwarf_getsrc_file",
- dwarf_getsrc_file (module_dwarf,
- srcfile, lineno, 0,
- &srcsp, &nsrcs));
+ if (line_type == RELATIVE)
+ {
+ Dwarf_Addr addr;
+ Dwarf_Line *line;
+ int line_number;
+
+ dwarf_assert ("dwarf_entrypc", dwarf_entrypc (this->function, &addr));
+ line = dwarf_getsrc_die (this->cu, addr);
+ dwarf_assert ("dwarf_getsrc_die", line == NULL);
+ dwarf_assert ("dwarf_lineno", dwarf_lineno (line, &line_number));
+ lineno += line_number;
+ }
+ else if (line_type == WILDCARD)
+ function_line (&lineno);
+
+ for (int l = lineno; ; l = l + 1)
+ {
+ dwarf_assert ("dwarf_getsrc_file",
+ dwarf_getsrc_file (module_dwarf,
+ srcfile, l, 0,
+ &srcsp, &nsrcs));
- // NB: Formerly, we used to filter, because:
+ if (line_type == WILDCARD || line_type == RANGE)
+ {
+ Dwarf_Addr line_addr;
+ dwarf_lineno (srcsp [0], &lineno);
+ if (lineno != l)
+ continue;
+ dwarf_lineaddr (srcsp [0], &line_addr);
+ if (dwarf_haspc (function, line_addr) != 1)
+ break;
+ }
- // dwarf_getsrc_file gets one *near hits* for line numbers, not
- // exact matches. For example, an existing file but a nonexistent
- // line number will be rounded up to the next definition in that
- // file. This may be similar to the GDB breakpoint algorithm, but
- // we don't want to be so fuzzy in systemtap land. So we filter.
+ // NB: Formerly, we used to filter, because:
- // But we now see the error of our ways, and skip this filtering.
+ // dwarf_getsrc_file gets one *near hits* for line numbers, not
+ // exact matches. For example, an existing file but a nonexistent
+ // line number will be rounded up to the next definition in that
+ // file. This may be similar to the GDB breakpoint algorithm, but
+ // we don't want to be so fuzzy in systemtap land. So we filter.
- // XXX: the code also fails to match e.g. inline function
- // definitions when the srcfile is a header file rather than the
- // CU name.
+ // But we now see the error of our ways, and skip this filtering.
- size_t remaining_nsrcs = nsrcs;
-#if 0
- for (size_t i = 0; i < nsrcs; ++i)
- {
- int l_no;
- Dwarf_Line* l = srcsp[i];
- dwarf_assert ("dwarf_lineno", dwarf_lineno (l, & l_no));
- if (l_no != lineno)
- {
- if (sess.verbose > 3)
- clog << "skipping line number mismatch "
- << "(" << l_no << " vs " << lineno << ")"
- << " in file '" << srcfile << "'"
- << "\n";
- srcsp[i] = 0;
- remaining_nsrcs --;
- }
- }
-#endif
+ // XXX: the code also fails to match e.g. inline function
+ // definitions when the srcfile is a header file rather than the
+ // CU name.
- if (need_single_match && remaining_nsrcs > 1)
- {
- // We wanted a single line record (a unique address for the
- // line) and we got a bunch of line records. We're going to
- // skip this probe (throw an exception) but before we throw
- // we're going to look around a bit to see if there's a low or
- // high line number nearby which *doesn't* have this problem,
- // so we can give the user some advice.
-
- int lo_try = -1;
- int hi_try = -1;
- for (size_t i = 1; i < 6; ++i)
+ size_t remaining_nsrcs = nsrcs;
+
+ if (need_single_match && remaining_nsrcs > 1)
{
- if (lo_try == -1 && has_single_line_record(q, srcfile, lineno - i))
- lo_try = lineno - i;
+ // We wanted a single line record (a unique address for the
+ // line) and we got a bunch of line records. We're going to
+ // skip this probe (throw an exception) but before we throw
+ // we're going to look around a bit to see if there's a low or
+ // high line number nearby which *doesn't* have this problem,
+ // so we can give the user some advice.
+
+ int lo_try = -1;
+ int hi_try = -1;
+ for (size_t i = 1; i < 6; ++i)
+ {
+ if (lo_try == -1 && has_single_line_record(q, srcfile, lineno - i))
+ lo_try = lineno - i;
- if (hi_try == -1 && has_single_line_record(q, srcfile, lineno + i))
- hi_try = lineno + i;
- }
+ if (hi_try == -1 && has_single_line_record(q, srcfile, lineno + i))
+ hi_try = lineno + i;
+ }
- stringstream advice;
- advice << "multiple addresses for " << srcfile << ":" << lineno;
- if (lo_try > 0 || hi_try > 0)
- {
- advice << " (try ";
- if (lo_try > 0)
- advice << srcfile << ":" << lo_try;
- if (lo_try > 0 && hi_try > 0)
- advice << " or ";
- if (hi_try > 0)
- advice << srcfile << ":" << hi_try;
- advice << ")";
- }
- throw semantic_error (advice.str());
- }
+ stringstream advice;
+ advice << "multiple addresses for " << srcfile << ":" << lineno;
+ if (lo_try > 0 || hi_try > 0)
+ {
+ advice << " (try ";
+ if (lo_try > 0)
+ advice << srcfile << ":" << lo_try;
+ if (lo_try > 0 && hi_try > 0)
+ advice << " or ";
+ if (hi_try > 0)
+ advice << srcfile << ":" << hi_try;
+ advice << ")";
+ }
+ throw semantic_error (advice.str());
+ }
- try
- {
- for (size_t i = 0; i < nsrcs; ++i)
+ try
{
- if (pending_interrupts) return;
- if (srcsp [i]) // skip over mismatched lines
- callback (srcsp[i], data);
+ for (size_t i = 0; i < nsrcs; ++i)
+ {
+ if (pending_interrupts) return;
+ if (srcsp [i]) // skip over mismatched lines
+ callback (dwarf_line_t(srcsp[i]), data);
+ }
}
- }
- catch (...)
- {
- free (srcsp);
- throw;
+ catch (...)
+ {
+ free (srcsp);
+ throw;
+ }
+ if (line_type != WILDCARD || l == lines[1])
+ break;
}
free (srcsp);
}
@@ -1316,23 +1337,23 @@ struct dwflpp
if (func->decl_file == 0) func->decl_file = "";
unsigned entrypc_srcline_idx = 0;
- Dwarf_Line* entrypc_srcline = 0;
+ dwarf_line_t entrypc_srcline;
// open-code binary search for exact match
{
unsigned l = 0, h = nlines;
while (l < h)
{
entrypc_srcline_idx = (l + h) / 2;
- Dwarf_Addr addr;
- Dwarf_Line *lr = dwarf_onesrcline(lines, entrypc_srcline_idx);
- dwarf_lineaddr (lr, &addr);
+ const dwarf_line_t lr(dwarf_onesrcline(lines,
+ entrypc_srcline_idx));
+ Dwarf_Addr addr = lr.addr();
if (addr == entrypc) { entrypc_srcline = lr; break; }
else if (l + 1 == h) { break; } // ran off bottom of tree
else if (addr < entrypc) { l = entrypc_srcline_idx; }
else { h = entrypc_srcline_idx; }
}
}
- if (entrypc_srcline == 0)
+ if (!entrypc_srcline)
throw semantic_error ("missing entrypc dwarf line record for function '"
+ func->name + "'");
@@ -1357,13 +1378,10 @@ struct dwflpp
bool ranoff_end = false;
while (postprologue_srcline_idx < nlines)
{
- Dwarf_Addr postprologue_addr;
- Dwarf_Line *lr = dwarf_onesrcline(lines, postprologue_srcline_idx);
- dwarf_lineaddr (lr, &postprologue_addr);
- const char* postprologue_file = dwarf_linesrc (lr, NULL, NULL);
- int postprologue_lineno;
- dwfl_assert ("dwarf_lineno",
- dwarf_lineno (lr, & postprologue_lineno));
+ dwarf_line_t lr(dwarf_onesrcline(lines, postprologue_srcline_idx));
+ Dwarf_Addr postprologue_addr = lr.addr();
+ const char* postprologue_file = lr.linesrc();
+ int postprologue_lineno = lr.lineno();
if (sess.verbose>2)
clog << "checking line record 0x" << hex << postprologue_addr << dec
@@ -1485,9 +1503,9 @@ struct dwflpp
dwarf_decl_line (function, linep);
}
- bool die_has_pc (Dwarf_Die * die, Dwarf_Addr pc)
+ bool die_has_pc (Dwarf_Die & die, Dwarf_Addr pc)
{
- int res = dwarf_haspc (die, pc);
+ int res = dwarf_haspc (&die, pc);
if (res == -1)
dwarf_assert ("dwarf_haspc", res);
return res == 1;
@@ -1524,19 +1542,19 @@ struct dwflpp
// We emit a comment approximating the variable+offset expression that
// relocatable module probing code will need to have.
Dwfl_Module *mod = dwfl_addrmodule (dwfl, address);
- dwfl_assert ("dwfl_addrmodule", mod == NULL);
+ dwfl_assert ("dwfl_addrmodule", mod);
int n = dwfl_module_relocations (mod);
- dwfl_assert ("dwfl_module_relocations", n < 0);
+ dwfl_assert ("dwfl_module_relocations", n >= 0);
int i = dwfl_module_relocate_address (mod, &address);
- dwfl_assert ("dwfl_module_relocate_address", i < 0);
+ dwfl_assert ("dwfl_module_relocate_address", i >= 0);
const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
- dwfl_assert ("dwfl_module_info", modname == NULL);
+ dwfl_assert ("dwfl_module_info", modname);
const char *secname = dwfl_module_relocation_info (mod, i, NULL);
if (n > 0 && !(n == 1 && secname == NULL))
{
- dwfl_assert ("dwfl_module_relocation_info", secname == NULL);
+ dwfl_assert ("dwfl_module_relocation_info", secname);
if (n > 1 || secname[0] != '\0')
{
// This gives us the module name, and section name within the
@@ -1581,7 +1599,6 @@ struct dwflpp
void print_locals(Dwarf_Die *die, ostream &o)
{
// Try to get the first child of die.
- bool local_found = false;
Dwarf_Die child;
if (dwarf_child (die, &child) == 0)
{
@@ -1594,7 +1611,6 @@ struct dwflpp
case DW_TAG_variable:
case DW_TAG_formal_parameter:
o << " " << dwarf_diename (&child);
- local_found = true;
break;
default:
break;
@@ -1602,9 +1618,6 @@ struct dwflpp
}
while (dwarf_siblingof (&child, &child) == 0);
}
-
- if (! local_found)
- o << " (none found)";
}
Dwarf_Attribute *
@@ -1642,8 +1655,7 @@ struct dwflpp
print_locals (scopes, alternatives);
throw semantic_error ("unable to find local '" + local + "'"
+ " near pc " + lex_cast_hex<string>(pc)
- + " (alternatives:" + alternatives.str ()
- + ")");
+ + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")));
}
for (int inner = 0; inner < nscopes; ++inner)
@@ -2177,8 +2189,10 @@ struct dwflpp
}
};
-module_cache_t dwflpp::module_cache;
-bool dwflpp::ignore_vmlinux = false;
+
+systemtap_session* dwflpp::this_session = 0; // XXX: used only due to elfutils shortcoming
+
+
enum
@@ -2252,7 +2266,7 @@ struct base_query
probe * base_probe,
probe_point * base_loc,
dwflpp & dw,
- map<string, literal *> const & params,
+ literal_map_t const & params,
vector<derived_probe *> & results);
virtual ~base_query() {}
@@ -2263,13 +2277,13 @@ struct base_query
vector<derived_probe *> & results;
// Parameter extractors.
- static bool has_null_param(map<string, literal *> const & params,
+ static bool has_null_param(literal_map_t const & params,
string const & k);
- static bool get_string_param(map<string, literal *> const & params,
+ static bool get_string_param(literal_map_t const & params,
string const & k, string & v);
- static bool get_number_param(map<string, literal *> const & params,
+ static bool get_number_param(literal_map_t const & params,
string const & k, long & v);
- static bool get_number_param(map<string, literal *> const & params,
+ static bool get_number_param(literal_map_t const & params,
string const & k, Dwarf_Addr & v);
// Extracted parameters.
@@ -2284,7 +2298,7 @@ base_query::base_query(systemtap_session & sess,
probe * base_probe,
probe_point * base_loc,
dwflpp & dw,
- map<string, literal *> const & params,
+ literal_map_t const & params,
vector<derived_probe *> & results)
: sess(sess), base_probe(base_probe), base_loc(base_loc), dw(dw),
results(results)
@@ -2301,7 +2315,7 @@ base_query::base_query(systemtap_session & sess,
}
bool
-base_query::has_null_param(map<string, literal *> const & params,
+base_query::has_null_param(literal_map_t const & params,
string const & k)
{
return derived_probe_builder::has_null_param(params, k);
@@ -2309,7 +2323,7 @@ base_query::has_null_param(map<string, literal *> const & params,
bool
-base_query::get_string_param(map<string, literal *> const & params,
+base_query::get_string_param(literal_map_t const & params,
string const & k, string & v)
{
return derived_probe_builder::get_param (params, k, v);
@@ -2317,7 +2331,7 @@ base_query::get_string_param(map<string, literal *> const & params,
bool
-base_query::get_number_param(map<string, literal *> const & params,
+base_query::get_number_param(literal_map_t const & params,
string const & k, long & v)
{
int64_t value;
@@ -2328,7 +2342,7 @@ base_query::get_number_param(map<string, literal *> const & params,
bool
-base_query::get_number_param(map<string, literal *> const & params,
+base_query::get_number_param(literal_map_t const & params,
string const & k, Dwarf_Addr & v)
{
int64_t value;
@@ -2337,6 +2351,8 @@ base_query::get_number_param(map<string, literal *> const & params,
return present;
}
+typedef map<Dwarf_Addr, inline_instance_info> inline_instance_map_t;
+typedef map<Dwarf_Addr, func_info> func_info_map_t;
struct dwarf_query : public base_query
{
@@ -2344,7 +2360,7 @@ struct dwarf_query : public base_query
probe * base_probe,
probe_point * base_loc,
dwflpp & dw,
- map<string, literal *> const & params,
+ literal_map_t const & params,
vector<derived_probe *> & results);
virtual void handle_query_module();
@@ -2404,14 +2420,15 @@ struct dwarf_query : public base_query
function_spec_type spec_type;
string function;
string file;
- int line;
+ line_t line_type;
+ int line[2];
bool query_done; // Found exact match
set<char const *> filtered_srcfiles;
// Map official entrypc -> func_info object
- map<Dwarf_Addr, inline_instance_info> filtered_inlines;
- map<Dwarf_Addr, func_info> filtered_functions;
+ inline_instance_map_t filtered_inlines;
+ func_info_map_t filtered_functions;
bool choose_next_line;
Dwarf_Addr entrypc_for_next_line;
};
@@ -2451,14 +2468,13 @@ dwflpp::has_single_line_record (dwarf_query * q, char const * srcfile, int linen
// We also try to filter out lines that leave the selected
// functions (if any).
- Dwarf_Line *line = srcsp[0];
- Dwarf_Addr addr;
- dwarf_lineaddr (line, &addr);
+ dwarf_line_t line(srcsp[0]);
+ Dwarf_Addr addr = line.addr();
- for (map<Dwarf_Addr, func_info>::iterator i = q->filtered_functions.begin();
+ for (func_info_map_t::iterator i = q->filtered_functions.begin();
i != q->filtered_functions.end(); ++i)
{
- if (q->dw.die_has_pc (&(i->second.die), addr))
+ if (q->dw.die_has_pc (i->second.die, addr))
{
if (q->sess.verbose>4)
clog << "alternative line " << lineno << " accepted: fn=" << i->second.name << endl;
@@ -2466,10 +2482,10 @@ dwflpp::has_single_line_record (dwarf_query * q, char const * srcfile, int linen
}
}
- for (map<Dwarf_Addr, inline_instance_info>::iterator i = q->filtered_inlines.begin();
+ for (inline_instance_map_t::iterator i = q->filtered_inlines.begin();
i != q->filtered_inlines.end(); ++i)
{
- if (q->dw.die_has_pc (&(i->second.die), addr))
+ if (q->dw.die_has_pc (i->second.die, addr))
{
if (sess.verbose>4)
clog << "alternative line " << lineno << " accepted: ifn=" << i->second.name << endl;
@@ -2570,7 +2586,7 @@ struct dwarf_builder: public derived_probe_builder
virtual void build(systemtap_session & sess,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results);
};
@@ -2579,7 +2595,7 @@ dwarf_query::dwarf_query(systemtap_session & sess,
probe * base_probe,
probe_point * base_loc,
dwflpp & dw,
- map<string, literal *> const & params,
+ literal_map_t const & params,
vector<derived_probe *> & results)
: base_query(sess, base_probe, base_loc, dw, params, results)
{
@@ -2871,11 +2887,12 @@ dwarf_query::parse_function_spec(string & spec)
function.clear();
file.clear();
- line = 0;
+ line[0] = 0;
+ line[1] = 0;
while (i != e && *i != '@')
{
- if (*i == ':')
+ if (*i == ':' || *i == '+')
goto bad;
function += *i++;
}
@@ -2892,8 +2909,17 @@ dwarf_query::parse_function_spec(string & spec)
if (i++ == e)
goto bad;
- while (i != e && *i != ':')
+ while (i != e && *i != ':' && *i != '+')
file += *i++;
+ if (*i == ':')
+ {
+ if (*(i + 1) == '*')
+ line_type = WILDCARD;
+ else
+ line_type = ABSOLUTE;
+ }
+ else if (*i == '+')
+ line_type = RELATIVE;
if (i == e)
{
@@ -2910,7 +2936,22 @@ dwarf_query::parse_function_spec(string & spec)
try
{
- line = lex_cast<int>(string(i, e));
+ if (line_type != WILDCARD)
+ {
+ string::const_iterator dash = i;
+
+ 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 (sess.verbose>2)
clog << "parsed '" << spec
<< "' -> func '"<< function
@@ -3016,7 +3057,7 @@ string dwarf_query::get_blacklist_section(Dwarf_Addr addr)
{
Elf_Scn* scn = 0;
size_t shstrndx;
- dw.dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx));
+ dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx));
while ((scn = elf_nextscn (elf, scn)) != NULL)
{
GElf_Shdr shdr_mem;
@@ -3268,20 +3309,18 @@ query_func_info (Dwarf_Addr entrypc,
static void
-query_srcfile_line (Dwarf_Line * line, void * arg)
+query_srcfile_line (const dwarf_line_t& line, void * arg)
{
dwarf_query * q = static_cast<dwarf_query *>(arg);
- Dwarf_Addr addr;
- dwarf_lineaddr(line, &addr);
+ Dwarf_Addr addr = line.addr();
- int lineno;
- dwarf_lineno (line, &lineno);
+ int lineno = line.lineno();
- for (map<Dwarf_Addr, func_info>::iterator i = q->filtered_functions.begin();
+ for (func_info_map_t::iterator i = q->filtered_functions.begin();
i != q->filtered_functions.end(); ++i)
{
- if (q->dw.die_has_pc (&(i->second.die), addr))
+ if (q->dw.die_has_pc (i->second.die, addr))
{
if (q->sess.verbose>3)
clog << "function DIE lands on srcfile\n";
@@ -3294,17 +3333,17 @@ query_srcfile_line (Dwarf_Line * line, void * arg)
}
}
- for (map<Dwarf_Addr, inline_instance_info>::iterator i
+ for (inline_instance_map_t::iterator i
= q->filtered_inlines.begin();
i != q->filtered_inlines.end(); ++i)
{
- if (q->dw.die_has_pc (&(i->second.die), addr))
+ if (q->dw.die_has_pc (i->second.die, addr))
{
if (q->sess.verbose>3)
clog << "inline instance DIE lands on srcfile\n";
if (q->has_statement_str)
query_statement (i->second.name, i->second.decl_file,
- q->line, &(i->second.die), addr, q);
+ q->line[0], &(i->second.die), addr, q);
else
query_inline_instance_info (i->first, i->second, q);
}
@@ -3390,7 +3429,7 @@ query_dwarf_func (Dwarf_Die * func, void * arg)
Dwarf_Die d;
q->dw.function_die (&d);
- if (q->dw.die_has_pc (&d, query_addr))
+ if (q->dw.die_has_pc (d, query_addr))
record_this_function = true;
}
@@ -3476,7 +3515,24 @@ query_cu (Dwarf_Die * cudie, void * arg)
if (q->filtered_srcfiles.empty())
return DWARF_CB_OK;
}
-
+ // Verify that a raw address matches the beginning of a
+ // statement. This is a somewhat lame check that the address
+ // is at the start of an assembly instruction.
+ if (q->has_statement_num)
+ {
+ Dwarf_Addr queryaddr = q->statement_num_val;
+ dwarf_line_t address_line(dwarf_getsrc_die(cudie, queryaddr));
+ Dwarf_Addr lineaddr = 0;
+ if (address_line)
+ lineaddr = address_line.addr();
+ if (!address_line || lineaddr != queryaddr)
+ {
+ stringstream msg;
+ msg << "address 0x" << hex << queryaddr
+ << "does not match the begining of a statement";
+ throw semantic_error(msg.str());
+ }
+ }
// Pick up [entrypc, name, DIE] tuples for all the functions
// matching the query, and fill in the prologue endings of them
// all in a single pass.
@@ -3497,18 +3553,18 @@ query_cu (Dwarf_Die * cudie, void * arg)
for (set<char const *>::const_iterator i = q->filtered_srcfiles.begin();
i != q->filtered_srcfiles.end(); ++i)
q->dw.iterate_over_srcfile_lines (*i, q->line, q->has_statement_str,
- query_srcfile_line, q);
+ q->line_type, query_srcfile_line, q);
}
else
{
// Otherwise, simply probe all resolved functions.
- for (map<Dwarf_Addr, func_info>::iterator i = q->filtered_functions.begin();
+ for (func_info_map_t::iterator i = q->filtered_functions.begin();
i != q->filtered_functions.end(); ++i)
query_func_info (i->first, i->second, q);
// And all inline instances (if we're not excluding inlines with ".call")
if (! q->has_call)
- for (map<Dwarf_Addr, inline_instance_info>::iterator i
+ for (inline_instance_map_t::iterator i
= q->filtered_inlines.begin(); i != q->filtered_inlines.end(); ++i)
query_inline_instance_info (i->first, i->second, q);
}
@@ -3576,7 +3632,7 @@ validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q)
GElf_Ehdr ehdr_mem;
GElf_Ehdr* em = gelf_getehdr (elf, &ehdr_mem);
- if (em == 0) { q->dw.dwfl_assert ("dwfl_getehdr", dwfl_errno()); }
+ if (em == 0) { dwfl_assert ("dwfl_getehdr", dwfl_errno()); }
int elf_machine = em->e_machine;
const char* debug_filename = "";
const char* main_filename = "";
@@ -3681,8 +3737,8 @@ dwflpp::query_modules(dwarf_query *q)
{
cache_modules_dwarf();
- map<string, module_info*>::iterator i = module_cache.cache.find(name);
- if (i != module_cache.cache.end())
+ map<string, module_info*>::iterator i = sess.module_cache->cache.find(name);
+ if (i != sess.module_cache->cache.end())
{
module_info *mi = i->second;
query_module(mi->mod, mi, name.c_str(), mi->addr, q);
@@ -4621,7 +4677,7 @@ void
dwarf_builder::build(systemtap_session & sess,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results)
{
// NB: the kernel/user dwlfpp objects are long-lived.
@@ -4697,12 +4753,18 @@ symbol_table::~symbol_table()
}
void
-symbol_table::add_symbol(const char *name, Dwarf_Addr addr,
- Dwarf_Addr *high_addr)
+symbol_table::add_symbol(const char *name, bool weak, Dwarf_Addr addr,
+ Dwarf_Addr *high_addr)
{
+#ifdef __powerpc__
+ // Map ".sys_foo" to "sys_foo".
+ if (name[0] == '.')
+ name++;
+#endif
func_info *fi = new func_info();
fi->addr = addr;
fi->name = name;
+ fi->weak = weak;
map_by_name[fi->name] = fi;
// TODO: Use a multimap in case there are multiple static
// functions with the same name?
@@ -4753,8 +4815,8 @@ symbol_table::read_symbols(FILE *f, const string& path)
free(mod);
goto done;
}
- if (type == 'T' || type == 't')
- add_symbol(name, (Dwarf_Addr) addr, &high_addr);
+ if (type == 'T' || type == 't' || type == 'W')
+ add_symbol(name, (type == 'W'), (Dwarf_Addr) addr, &high_addr);
free(name);
}
@@ -4809,6 +4871,55 @@ symbol_table::read_from_text_file(const string& path)
return status;
}
+void
+symbol_table::prepare_section_rejection(Dwfl_Module *mod)
+{
+#ifdef __powerpc__
+ /*
+ * The .opd section contains function descriptors that can look
+ * just like function entry points. For example, there's a function
+ * descriptor called "do_exit" that links to the entry point ".do_exit".
+ * Reject all symbols in .opd.
+ */
+ opd_section = SHN_UNDEF;
+ Dwarf_Addr bias;
+ Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (mod, &bias))
+ ?: dwfl_module_getelf (mod, &bias));
+ Elf_Scn* scn = 0;
+ size_t shstrndx;
+
+ if (!elf)
+ return;
+ if (elf_getshstrndx(elf, &shstrndx) != 0)
+ return;
+ while ((scn = elf_nextscn(elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
+ if (!shdr)
+ continue;
+ const char *name = elf_strptr(elf, shstrndx, shdr->sh_name);
+ if (!strcmp(name, ".opd"))
+ {
+ opd_section = elf_ndxscn(scn);
+ return;
+ }
+ }
+#endif
+}
+
+bool
+symbol_table::reject_section(GElf_Word section)
+{
+ if (section == SHN_UNDEF)
+ return true;
+#ifdef __powerpc__
+ if (section == opd_section)
+ return true;
+#endif
+ return false;
+}
+
enum info_status
symbol_table::get_from_elf()
{
@@ -4816,12 +4927,16 @@ symbol_table::get_from_elf()
Dwfl_Module *mod = mod_info->mod;
int syments = dwfl_module_getsymtab(mod);
assert(syments);
+ prepare_section_rejection(mod);
for (int i = 1; i < syments; ++i)
{
GElf_Sym sym;
- const char *name = dwfl_module_getsym(mod, i, &sym, NULL);
- if (name && GELF_ST_TYPE(sym.st_info) == STT_FUNC)
- add_symbol(name, sym.st_value, &high_addr);
+ GElf_Word section;
+ const char *name = dwfl_module_getsym(mod, i, &sym, &section);
+ if (name && GELF_ST_TYPE(sym.st_info) == STT_FUNC &&
+ !reject_section(section))
+ add_symbol(name, (GELF_ST_BIND(sym.st_info) == STB_WEAK),
+ sym.st_value, &high_addr);
}
return info_present;
}
@@ -4913,6 +5028,33 @@ symbol_table::lookup_symbol_address(const string& name)
return 0;
}
+// This is the kernel symbol table. The kernel macro cond_syscall creates
+// a weak symbol for each system call and maps it to sys_ni_syscall.
+// For system calls not implemented elsewhere, this weak symbol shows up
+// in the kernel symbol table. Following the precedent of dwarfful stap,
+// we refuse to consider such symbols. Here we delete them from our
+// symbol table.
+// TODO: Consider generalizing this and/or making it part of blacklist
+// processing.
+void
+symbol_table::purge_syscall_stubs()
+{
+ Dwarf_Addr stub_addr = lookup_symbol_address("sys_ni_syscall");
+ if (stub_addr == 0)
+ return;
+ for (size_t i = 0; i < list_by_addr.size(); i++)
+ {
+ func_info *fi = list_by_addr.at(i);
+ if (fi->weak && fi->addr == stub_addr && fi->name != "sys_ni_syscall")
+ {
+ list_by_addr.erase(list_by_addr.begin()+i);
+ map_by_name.erase(fi->name);
+ delete fi;
+ i--;
+ }
+ }
+}
+
void
module_info::get_symtab(dwarf_query *q)
{
@@ -4968,6 +5110,9 @@ module_info::get_symtab(dwarf_query *q)
// precedes the call to query_module_symtab(). So we should never read
// a module's symbol table without first having tried to get its dwarf.
sym_table->mark_dwarf_redundancies(&q->dw);
+
+ if (name == TOK_KERNEL)
+ sym_table->purge_syscall_stubs();
}
module_info::~module_info()
@@ -5052,25 +5197,19 @@ task_finder_derived_probe_group::emit_module_exit (systemtap_session& s)
// utrace user-space probes
// ------------------------------------------------------------------------
-// Since we don't have access to <linux/utrace.h>, we'll have to
-// define our own version of the UTRACE_EVENT flags.
+static string TOK_THREAD("thread");
+static string TOK_SYSCALL("syscall");
+
+// Note that these flags don't match up exactly with UTRACE_EVENT
+// flags (and that's OK).
enum utrace_derived_probe_flags {
UDPF_NONE,
- UDPF_QUIESCE, // UTRACE_EVENT(QUIESCE)
- UDPF_REAP, // UTRACE_EVENT(REAP)
- UDPF_CLONE, // UTRACE_EVENT(CLONE)
- UDPF_VFORK_DONE, // UTRACE_EVENT(VFORK_DONE)
- UDPF_EXEC, // UTRACE_EVENT(EXEC)
- UDPF_EXIT, // UTRACE_EVENT(EXIT)
- UDPF_DEATH, // UTRACE_EVENT(DEATH)
- UDPF_SYSCALL_ENTRY, // UTRACE_EVENT(SYSCALL_ENTRY)
- UDPF_SYSCALL_EXIT, // UTRACE_EVENT(SYSCALL_EXIT)
- UDPF_SIGNAL, // UTRACE_EVENT(SIGNAL)
- UDPF_SIGNAL_IGN, // UTRACE_EVENT(SIGNAL_IGN)
- UDPF_SIGNAL_STOP, // UTRACE_EVENT(SIGNAL_STOP)
- UDPF_SIGNAL_TERM, // UTRACE_EVENT(SIGNAL_TERM)
- UDPF_SIGNAL_CORE, // UTRACE_EVENT(SIGNAL_CORE)
- UDPF_JCTL, // UTRACE_EVENT(JCTL)
+ UDPF_BEGIN, // process begin
+ UDPF_END, // process end
+ UDPF_THREAD_BEGIN, // thread begin
+ UDPF_THREAD_END, // thread end
+ UDPF_SYSCALL, // syscall entry
+ UDPF_SYSCALL_RETURN, // syscall exit
UDPF_NFLAGS
};
@@ -5100,6 +5239,9 @@ private:
bool flags_seen[UDPF_NFLAGS];
void emit_probe_decl (systemtap_session& s, utrace_derived_probe *p);
+ void emit_vm_callback_probe_decl (systemtap_session& s, bool has_path,
+ string path, int64_t pid,
+ string vm_callback);
public:
utrace_derived_probe_group(): num_probes(0), flags_seen() { }
@@ -5144,15 +5286,9 @@ void
utrace_derived_probe::join_group (systemtap_session& s)
{
if (! s.utrace_derived_probes)
- {
+ {
s.utrace_derived_probes = new utrace_derived_probe_group ();
-
- // Make sure <linux/tracehook.h> is included early.
- embeddedcode *ec = new embeddedcode;
- ec->tok = NULL;
- ec->code = string("#include <linux/tracehook.h>\n");
- s.embeds.push_back(ec);
- }
+ }
s.utrace_derived_probes->enroll (this);
task_finder_derived_probe_group::create_session_group (s);
@@ -5164,7 +5300,7 @@ utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e)
{
assert(e->base_name.size() > 0 && e->base_name[0] == '$');
- if (flags != UDPF_SYSCALL_ENTRY && flags != UDPF_SYSCALL_EXIT)
+ if (flags != UDPF_SYSCALL && flags != UDPF_SYSCALL_RETURN)
throw semantic_error ("only \"process(PATH_OR_PID).syscall\" and \"process(PATH_OR_PID).syscall.return\" probes support target symbols",
e->tok);
@@ -5198,28 +5334,11 @@ utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e)
// Remember that we've seen a target variable.
target_symbol_seen = true;
- // Synthesize a function.
- functiondecl *fdecl = new functiondecl;
- fdecl->tok = e->tok;
- embeddedcode *ec = new embeddedcode;
- ec->tok = e->tok;
-
- string fname = (string("_utrace_syscall_get") + "_"
- + lex_cast<string>(tick++));
- string locvalue = "CONTEXT->data";
-
- ec->code = string("THIS->__retvalue = *tracehook_syscall_callno(CONTEXT->regs); /* pure */");
-
- fdecl->name = fname;
- fdecl->body = ec;
- fdecl->type = pe_long;
-
- sess.functions.push_back(fdecl);
-
- // Synthesize a functioncall.
+ // We're going to substitute a synthesized 'syscall_nr' function
+ // call for the '$syscall' reference.
functioncall* n = new functioncall;
n->tok = e->tok;
- n->function = fname;
+ n->function = "syscall_nr";
n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
provide <functioncall*> (this, n);
@@ -5232,7 +5351,7 @@ struct utrace_builder: public derived_probe_builder
virtual void build(systemtap_session & sess,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results)
{
string path;
@@ -5243,19 +5362,24 @@ struct utrace_builder: public derived_probe_builder
enum utrace_derived_probe_flags flags = UDPF_NONE;
assert (has_path || has_pid);
- if (has_null_param (parameters, "death"))
- flags = UDPF_DEATH;
- else if (has_null_param (parameters, "syscall"))
+ if (has_null_param (parameters, TOK_THREAD))
+ {
+ if (has_null_param (parameters, TOK_BEGIN))
+ flags = UDPF_THREAD_BEGIN;
+ else if (has_null_param (parameters, TOK_END))
+ flags = UDPF_THREAD_END;
+ }
+ else if (has_null_param (parameters, TOK_SYSCALL))
{
if (has_null_param (parameters, TOK_RETURN))
- flags = UDPF_SYSCALL_EXIT;
+ flags = UDPF_SYSCALL_RETURN;
else
- flags = UDPF_SYSCALL_ENTRY;
+ flags = UDPF_SYSCALL;
}
- else if (has_null_param (parameters, "clone"))
- flags = UDPF_CLONE;
- else if (has_null_param (parameters, "exec"))
- flags = UDPF_EXEC;
+ else if (has_null_param (parameters, TOK_BEGIN))
+ flags = UDPF_BEGIN;
+ else if (has_null_param (parameters, TOK_END))
+ flags = UDPF_END;
// If we have a path, we need to validate it.
if (has_path)
@@ -5338,6 +5462,7 @@ utrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
}
s.op->line() << " .callback=&_stp_utrace_probe_cb,";
+ s.op->line() << " .vm_callback=NULL,";
s.op->line() << " },";
s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ",";
s.op->line() << " .ph=&" << p->name << ",";
@@ -5345,29 +5470,46 @@ utrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
// Handle flags
switch (p->flags)
{
- case UDPF_CLONE:
- s.op->line() << " .ops={ .report_clone=stap_utrace_probe_clone, .report_death=stap_utrace_task_finder_report_death },";
- s.op->line() << " .flags=(UTRACE_EVENT(CLONE)|UTRACE_EVENT(DEATH)),";
+ // Look in _stp_utrace_probe_cb for description of why quiesce is
+ // used here.
+ case UDPF_BEGIN: // process begin
+ s.op->line() << " .flags=(UDPF_BEGIN),";
+ s.op->line() << " .ops={ .report_quiesce=stap_utrace_probe_quiesce },";
+ s.op->line() << " .events=(UTRACE_ACTION_QUIESCE|UTRACE_EVENT(QUIESCE)),";
break;
- case UDPF_EXEC:
- // Notice we're not setting up a .ops/.report_exec handler here.
- // Instead, we'll just call the probe directly when we get
- // notified the exec happened.
- s.op->line() << " .flags=(UTRACE_EVENT(EXEC)),";
+ case UDPF_THREAD_BEGIN: // thread begin
+ s.op->line() << " .flags=(UDPF_THREAD_BEGIN),";
+ s.op->line() << " .ops={ .report_quiesce=stap_utrace_probe_quiesce },";
+ s.op->line() << " .events=(UTRACE_ACTION_QUIESCE|UTRACE_EVENT(QUIESCE)),";
break;
- case UDPF_DEATH:
- // Notice we're not setting up a .ops/.report_death handler
- // here. Instead, we'll just call the probe directly when we
- // get notified the death happened.
- s.op->line() << " .flags=(UTRACE_EVENT(DEATH)),";
+
+ // Notice we're not setting up a .ops/.report_death handler for
+ // either UDPF_END or UDPF_THREAD_END. Instead, we'll just call
+ // the probe directly when we get notified.
+ case UDPF_END: // process end
+ s.op->line() << " .flags=(UDPF_END),";
break;
- case UDPF_SYSCALL_ENTRY:
+ case UDPF_THREAD_END: // thread end
+ s.op->line() << " .flags=(UDPF_THREAD_END),";
+ break;
+
+ // For UDPF_SYSCALL/UDPF_SYSCALL_RETURN probes, the .report_death
+ // handler isn't strictly necessary. However, it helps to keep
+ // our attaches/detaches symmetrical.
+ case UDPF_SYSCALL:
+ s.op->line() << " .flags=(UDPF_SYSCALL),";
s.op->line() << " .ops={ .report_syscall_entry=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
- s.op->line() << " .flags=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),";
+ s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),";
break;
- case UDPF_SYSCALL_EXIT:
+ case UDPF_SYSCALL_RETURN:
+ s.op->line() << " .flags=(UDPF_SYSCALL_RETURN),";
s.op->line() << " .ops={ .report_syscall_exit=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
- s.op->line() << " .flags=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),";
+ s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),";
+ break;
+ case UDPF_NONE:
+ s.op->line() << " .flags=(UDPF_NONE),";
+ s.op->line() << " .ops={ },";
+ s.op->line() << " .events=0,";
break;
default:
throw semantic_error ("bad utrace probe flag");
@@ -5379,6 +5521,40 @@ utrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
void
+utrace_derived_probe_group::emit_vm_callback_probe_decl (systemtap_session& s,
+ bool has_path,
+ string path,
+ int64_t pid,
+ string vm_callback)
+{
+ s.op->newline() << "{";
+ s.op->line() << " .tgt={";
+
+ if (has_path)
+ {
+ s.op->line() << " .pathname=\"" << path << "\",";
+ s.op->line() << " .pid=0,";
+ }
+ else
+ {
+ s.op->line() << " .pathname=NULL,";
+ s.op->line() << " .pid=" << pid << ",";
+ }
+
+ s.op->line() << " .callback=NULL,";
+ s.op->line() << " .vm_callback=&" << vm_callback << ",";
+ s.op->line() << " },";
+ s.op->line() << " .pp=\"internal\",";
+ s.op->line() << " .ph=NULL,";
+ s.op->line() << " .flags=(UDPF_NONE),";
+ s.op->line() << " .ops={ NULL },";
+ s.op->line() << " .events=0,";
+ s.op->line() << " .engine_attached=0,";
+ s.op->line() << " },";
+}
+
+
+void
utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
{
if (probes_by_path.empty() && probes_by_pid.empty())
@@ -5386,20 +5562,34 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline();
s.op->newline() << "/* ---- utrace probes ---- */";
+ s.op->newline() << "enum utrace_derived_probe_flags {";
+ s.op->indent(1);
+ s.op->newline() << "UDPF_NONE,";
+ s.op->newline() << "UDPF_BEGIN,";
+ s.op->newline() << "UDPF_END,";
+ s.op->newline() << "UDPF_THREAD_BEGIN,";
+ s.op->newline() << "UDPF_THREAD_END,";
+ s.op->newline() << "UDPF_SYSCALL,";
+ s.op->newline() << "UDPF_SYSCALL_RETURN,";
+ s.op->newline() << "UDPF_NFLAGS";
+ s.op->newline(-1) << "};";
+
s.op->newline() << "struct stap_utrace_probe {";
s.op->indent(1);
s.op->newline() << "struct stap_task_finder_target tgt;";
s.op->newline() << "const char *pp;";
s.op->newline() << "void (*ph) (struct context*);";
+ s.op->newline() << "enum utrace_derived_probe_flags flags;";
s.op->newline() << "struct utrace_engine_ops ops;";
- s.op->newline() << "unsigned long flags;";
+ s.op->newline() << "unsigned long events;";
s.op->newline() << "int engine_attached;";
s.op->newline(-1) << "};";
- // Output handler function for CLONE events
- if (flags_seen[UDPF_CLONE])
+
+ // Output handler function for UDPF_BEGIN and UDPF_THREAD_BEGIN
+ if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN])
{
- s.op->newline() << "static u32 stap_utrace_probe_clone(struct utrace_attached_engine *engine, struct task_struct *parent, unsigned long clone_flags, struct task_struct *child) {";
+ s.op->newline() << "static u32 stap_utrace_probe_quiesce(struct utrace_attached_engine *engine, struct task_struct *tsk) {";
s.op->indent(1);
s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;";
@@ -5410,12 +5600,15 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "(*p->ph) (c);";
common_probe_entryfn_epilogue (s.op);
- s.op->newline() << "return UTRACE_ACTION_RESUME;";
+ // UTRACE_ACTION_NEWSTATE not needed here to clear quiesce since
+ // we're detaching - utrace automatically restarts the thread.
+ s.op->newline() << "debug_task_finder_detach();";
+ s.op->newline() << "return UTRACE_ACTION_DETACH;";
s.op->newline(-1) << "}";
}
- // Output handler function for EXEC and DEATH events
- if (flags_seen[UDPF_EXEC] || flags_seen[UDPF_DEATH])
+ // Output handler function for UDPF_END and UDPF_THREAD_END
+ if (flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
{
s.op->newline() << "static void stap_utrace_probe_handler(struct task_struct *tsk, struct stap_utrace_probe *p) {";
s.op->indent(1);
@@ -5432,7 +5625,7 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
}
// Output handler function for SYSCALL_ENTRY and SYSCALL_EXIT events
- if (flags_seen[UDPF_SYSCALL_ENTRY] || flags_seen[UDPF_SYSCALL_EXIT])
+ if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
{
s.op->newline() << "static u32 stap_utrace_probe_syscall(struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
s.op->indent(1);
@@ -5450,9 +5643,9 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline(-1) << "}";
}
- // Output task finder callback routine that gets called for all
+ // Output task_finder callback routine that gets called for all
// utrace probe types.
- s.op->newline() << "static int _stp_utrace_probe_cb(struct task_struct *tsk, int register_p, struct stap_task_finder_target *tgt) {";
+ s.op->newline() << "static int _stp_utrace_probe_cb(struct task_struct *tsk, int register_p, int process_p, struct stap_task_finder_target *tgt) {";
s.op->indent(1);
s.op->newline() << "int rc = 0;";
s.op->newline() << "struct stap_utrace_probe *p = container_of(tgt, struct stap_utrace_probe, tgt);";
@@ -5463,74 +5656,135 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "switch (p->flags) {";
s.op->indent(1);
- // When registering an exec probe, we can't install a utrace engine,
- // since we're already in a exec event. So, we just call the probe
- // directly. Note that for existing threads, this won't really work
- // since our state isn't STAP_SESSION_RUNNING yet. But that's OK,
- // since this isn't really a 'exec' event - it is a notification
- // that task_finder found an interesting process.
- if (flags_seen[UDPF_EXEC])
- {
- s.op->newline() << "case UTRACE_EVENT(EXEC):";
+
+ // When receiving a UTRACE_EVENT(CLONE) event, we can't call the
+ // begin/thread.begin probe directly. So, we'll just attach an
+ // engine that waits for the thread to quiesce. When the thread
+ // quiesces, then call the probe.
+ if (flags_seen[UDPF_BEGIN])
+ {
+ s.op->newline() << "case UDPF_BEGIN:";
s.op->indent(1);
- s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
- s.op->newline() << "break;";
- s.op->indent(-1);
- }
- // For death probes, do nothing at registration time. We'll handle
- // these in the 'register_p == 0' case.
- if (flags_seen[UDPF_DEATH])
- {
- s.op->newline() << "case UTRACE_EVENT(DEATH):";
+ s.op->newline() << "if (process_p) {";
+ s.op->indent(1);
+ s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);";
+ s.op->newline() << "if (rc == 0) {";
s.op->indent(1);
+ s.op->newline() << "p->engine_attached = 1;";
+ s.op->newline(-1) << "}";
+ s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
- }
- // Attach an engine for CLONE, SYSCALL_ENTRY, and SYSCALL_EXIT events.
- if (flags_seen[UDPF_CLONE] || flags_seen[UDPF_SYSCALL_ENTRY]
- || flags_seen[UDPF_SYSCALL_EXIT])
- {
- s.op->newline() << "case (UTRACE_EVENT(CLONE)|UTRACE_EVENT(DEATH)):";
- s.op->newline() << "case (UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)):";
- s.op->newline() << "case (UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)):";
+ }
+ if (flags_seen[UDPF_THREAD_BEGIN])
+ {
+ s.op->newline() << "case UDPF_THREAD_BEGIN:";
s.op->indent(1);
- s.op->newline() << "engine = utrace_attach(tsk, UTRACE_ATTACH_CREATE, &p->ops, p);";
- s.op->newline() << "if (IS_ERR(engine)) {";
+ s.op->newline() << "if (! process_p) {";
s.op->indent(1);
- s.op->newline() << "int error = -PTR_ERR(engine);";
- s.op->newline() << "if (error != ENOENT) {";
+ s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);";
+ s.op->newline() << "if (rc == 0) {";
s.op->indent(1);
- s.op->newline() << "_stp_error(\"utrace_attach returned error %d on pid %d\", error, (int)tsk->pid);";
- s.op->newline() << "rc = error;";
+ s.op->newline() << "p->engine_attached = 1;";
s.op->newline(-1) << "}";
s.op->newline(-1) << "}";
- s.op->newline() << "else if (unlikely(engine == NULL)) {";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+
+ // For end/thread_end probes, do nothing at registration time.
+ // We'll handle these in the 'register_p == 0' case.
+ if (flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
+ {
+ s.op->newline() << "case UDPF_END:";
+ s.op->newline() << "case UDPF_THREAD_END:";
s.op->indent(1);
- s.op->newline() << "_stp_error(\"utrace_attach returned NULL on pid %d!\", (int)tsk->pid);";
- s.op->newline() << "rc = ENOENT;";
- s.op->newline(-1) << "}";
- s.op->newline() << "else {";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+
+ // Attach an engine for SYSCALL_ENTRY and SYSCALL_EXIT events.
+ if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
+ {
+ s.op->newline() << "case UDPF_SYSCALL:";
+ s.op->newline() << "case UDPF_SYSCALL_RETURN:";
+ s.op->indent(1);
+ s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);";
+ s.op->newline() << "if (rc == 0) {";
s.op->indent(1);
- s.op->newline() << "utrace_set_flags(tsk, engine, p->flags);";
s.op->newline() << "p->engine_attached = 1;";
s.op->newline(-1) << "}";
s.op->newline() << "break;";
s.op->indent(-1);
}
+
+ s.op->newline() << "default:";
+ s.op->indent(1);
+ s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
s.op->newline(-1) << "}";
s.op->newline(-1) << "}";
+
// Since this engine could be attached to multiple threads, don't
- // cleanup here. We'll cleanup at module unload time.
+ // call stap_utrace_detach_ops() here.
s.op->newline() << "else {";
s.op->indent(1);
+ s.op->newline() << "switch (p->flags) {";
+ s.op->indent(1);
// For death probes, go ahead and call the probe directly.
- if (flags_seen[UDPF_DEATH])
+ if (flags_seen[UDPF_END])
+ {
+ s.op->newline() << "case UDPF_END:";
+ s.op->indent(1);
+ s.op->newline() << "if (process_p) {";
+ s.op->indent(1);
+ s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+ if (flags_seen[UDPF_THREAD_END])
{
- s.op->newline() << "if (p->flags == UTRACE_EVENT(DEATH)) {";
+ s.op->newline() << "case UDPF_THREAD_END:";
+ s.op->indent(1);
+ s.op->newline() << "if (! process_p) {";
s.op->indent(1);
s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
s.op->newline(-1) << "}";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
}
+
+ // For begin/thread_begin probes, at deregistration time we'll try
+ // to detach. This will only be necessary if the new thread/process
+ // got killed before the probe got run in the UTRACE_EVENT(QUIESCE)
+ // handler.
+ if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN]
+ || flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
+ {
+ s.op->newline() << "case UDPF_BEGIN:";
+ s.op->newline() << "case UDPF_THREAD_BEGIN:";
+ s.op->newline() << "case UDPF_SYSCALL:";
+ s.op->newline() << "case UDPF_SYSCALL_RETURN:";
+ s.op->indent(1);
+ s.op->newline() << "engine = utrace_attach(tsk, UTRACE_ATTACH_MATCH_OPS, &p->ops, 0);";
+ s.op->newline() << "if (! IS_ERR(engine) && engine != NULL) {";
+ s.op->indent(1);
+ s.op->newline() << "utrace_detach(tsk, engine);";
+ s.op->newline() << "debug_task_finder_detach();";
+
+ s.op->newline(-1) << "}";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+
+ s.op->newline() << "default:";
+ s.op->indent(1);
+ s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ s.op->newline(-1) << "}";
s.op->newline(-1) << "}";
s.op->newline() << "return rc;";
s.op->newline(-1) << "}";
@@ -5544,6 +5798,14 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
for (p_b_path_iterator it = probes_by_path.begin();
it != probes_by_path.end(); it++)
{
+ // Emit a "fake" probe decl that is really a hook for to get
+ // our vm_callback called.
+ string path = it->first;
+ s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA";
+ emit_vm_callback_probe_decl (s, true, path, (int64_t)0,
+ "__stp_tf_vm_cb");
+ s.op->newline() << "#endif";
+
for (unsigned i = 0; i < it->second.size(); i++)
{
utrace_derived_probe *p = it->second[i];
@@ -5558,6 +5820,13 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
for (p_b_pid_iterator it = probes_by_pid.begin();
it != probes_by_pid.end(); it++)
{
+ // Emit a "fake" probe decl that is really a hook for to get
+ // our vm_callback called.
+ s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA";
+ emit_vm_callback_probe_decl (s, false, NULL, it->first,
+ "__stp_tf_vm_cb");
+ s.op->newline() << "#endif";
+
for (unsigned i = 0; i < it->second.size(); i++)
{
utrace_derived_probe *p = it->second[i];
@@ -5667,7 +5936,7 @@ struct uprobe_builder: public derived_probe_builder
virtual void build(systemtap_session & sess,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results)
{
int64_t process, address;
@@ -5802,6 +6071,8 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s)
// ------------------------------------------------------------------------
+static string TOK_TIMER("timer");
+
struct timer_derived_probe: public derived_probe
{
int64_t interval, randomize;
@@ -5983,7 +6254,7 @@ struct profile_builder: public derived_probe_builder
virtual void build(systemtap_session & sess,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const &,
+ literal_map_t const &,
vector<derived_probe *> & finished_results)
{
finished_results.push_back(new profile_derived_probe(sess, base, location));
@@ -6090,6 +6361,10 @@ profile_derived_probe_group::emit_module_exit (systemtap_session& s)
// ------------------------------------------------------------------------
+static string TOK_PROCFS("procfs");
+static string TOK_READ("read");
+static string TOK_WRITE("write");
+
struct procfs_derived_probe: public derived_probe
{
string path;
@@ -6496,7 +6771,7 @@ struct procfs_builder: public derived_probe_builder
virtual void build(systemtap_session & sess,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results);
};
@@ -6505,13 +6780,13 @@ void
procfs_builder::build(systemtap_session & sess,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results)
{
string path;
- bool has_procfs = get_param(parameters, "procfs", path);
- bool has_read = (parameters.find("read") != parameters.end());
- bool has_write = (parameters.find("write") != parameters.end());
+ bool has_procfs = get_param(parameters, TOK_PROCFS, path);
+ bool has_read = (parameters.find(TOK_READ) != parameters.end());
+ bool has_write = (parameters.find(TOK_WRITE) != parameters.end());
// If no procfs path, default to "command". The runtime will do
// this for us, but if we don't do it here, we'll think the
@@ -6568,6 +6843,8 @@ procfs_builder::build(systemtap_session & sess,
// statically inserted macro-based derived probes
// ------------------------------------------------------------------------
+static string TOK_MARK("mark");
+static string TOK_FORMAT("format");
struct mark_arg
{
@@ -6802,9 +7079,9 @@ mark_derived_probe::mark_derived_probe (systemtap_session &s,
{
// create synthetic probe point name; preserve condition
vector<probe_point::component*> comps;
- comps.push_back (new probe_point::component ("kernel"));
- comps.push_back (new probe_point::component ("mark", new literal_string (probe_name)));
- comps.push_back (new probe_point::component ("format", new literal_string (probe_format)));
+ comps.push_back (new probe_point::component (TOK_KERNEL));
+ comps.push_back (new probe_point::component (TOK_MARK, new literal_string (probe_name)));
+ comps.push_back (new probe_point::component (TOK_FORMAT, new literal_string (probe_format)));
this->sole_location()->components = comps;
// expand the marker format
@@ -7161,7 +7438,7 @@ public:
void build(systemtap_session & sess,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results);
};
@@ -7170,13 +7447,13 @@ void
mark_builder::build(systemtap_session & sess,
probe * base,
probe_point *loc,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results)
{
string mark_str_val;
- bool has_mark_str = get_param (parameters, "mark", mark_str_val);
+ bool has_mark_str = get_param (parameters, TOK_MARK, mark_str_val);
string mark_format_val;
- bool has_mark_format = get_param (parameters, "format", mark_format_val);
+ bool has_mark_format = get_param (parameters, TOK_FORMAT, mark_format_val);
assert (has_mark_str);
(void) has_mark_str;
@@ -7460,7 +7737,7 @@ struct timer_builder: public derived_probe_builder
{
virtual void build(systemtap_session & sess,
probe * base, probe_point * location,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results);
static void register_patterns(match_node *root);
@@ -7470,7 +7747,7 @@ void
timer_builder::build(systemtap_session & sess,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results)
{
int64_t period, rand=0;
@@ -7538,7 +7815,7 @@ timer_builder::register_patterns(match_node *root)
{
derived_probe_builder *builder = new timer_builder();
- root = root->bind("timer");
+ root = root->bind(TOK_TIMER);
root->bind_num("s")->bind(builder);
root->bind_num("s")->bind_num("randomize")->bind(builder);
@@ -7682,7 +7959,7 @@ struct perfmon_builder: public derived_probe_builder
virtual void build(systemtap_session & sess,
probe * base,
probe_point * location,
- std::map<std::string, literal *> const & parameters,
+ literal_map_t const & parameters,
vector<derived_probe *> & finished_results)
{
string event;
@@ -7994,18 +8271,19 @@ perfmon_derived_probe_group::emit_module_init (translator_output* o)
void
register_standard_tapsets(systemtap_session & s)
{
- s.pattern_root->bind("begin")->bind(new be_builder(BEGIN));
- s.pattern_root->bind_num("begin")->bind(new be_builder(BEGIN));
- s.pattern_root->bind("end")->bind(new be_builder(END));
- s.pattern_root->bind_num("end")->bind(new be_builder(END));
- s.pattern_root->bind("error")->bind(new be_builder(ERROR));
- s.pattern_root->bind_num("error")->bind(new be_builder(ERROR));
+ s.pattern_root->bind(TOK_BEGIN)->bind(new be_builder(BEGIN));
+ s.pattern_root->bind_num(TOK_BEGIN)->bind(new be_builder(BEGIN));
+ s.pattern_root->bind(TOK_END)->bind(new be_builder(END));
+ s.pattern_root->bind_num(TOK_END)->bind(new be_builder(END));
+ s.pattern_root->bind(TOK_ERROR)->bind(new be_builder(ERROR));
+ s.pattern_root->bind_num(TOK_ERROR)->bind(new be_builder(ERROR));
- s.pattern_root->bind("never")->bind(new never_builder());
+ s.pattern_root->bind(TOK_NEVER)->bind(new never_builder());
timer_builder::register_patterns(s.pattern_root);
- s.pattern_root->bind("timer")->bind("profile")->bind(new profile_builder());
- s.pattern_root->bind("perfmon")->bind_str("counter")->bind(new perfmon_builder());
+ s.pattern_root->bind(TOK_TIMER)->bind("profile")->bind(new profile_builder());
+ s.pattern_root->bind("perfmon")->bind_str("counter")
+ ->bind(new perfmon_builder());
// dwarf-based kernel/module parts
dwarf_derived_probe::register_patterns(s.pattern_root);
@@ -8019,37 +8297,44 @@ register_standard_tapsets(systemtap_session & s)
->bind(new uprobe_builder ());
// utrace user-space probes
- s.pattern_root->bind_str(TOK_PROCESS)->bind("clone")
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_BEGIN)
->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind("clone")
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_BEGIN)
->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind("exec")
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_END)
->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind("exec")
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_END)
->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind("syscall")
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN)
->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind("syscall")
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN)
->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind("syscall")->bind(TOK_RETURN)
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END)
->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind("syscall")->bind(TOK_RETURN)
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END)
->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind("death")
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL)
->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind("death")
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL)
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN)
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN)
->bind(new utrace_builder ());
// marker-based parts
- s.pattern_root->bind("kernel")->bind_str("mark")->bind(new mark_builder());
- s.pattern_root->bind("kernel")->bind_str("mark")->bind_str("format")
+ s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK)
+ ->bind(new mark_builder());
+ s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK)->bind_str(TOK_FORMAT)
->bind(new mark_builder());
// procfs parts
- s.pattern_root->bind("procfs")->bind("read")->bind(new procfs_builder());
- s.pattern_root->bind_str("procfs")->bind("read")->bind(new procfs_builder());
- s.pattern_root->bind("procfs")->bind("write")->bind(new procfs_builder());
- s.pattern_root->bind_str("procfs")->bind("write")->bind(new procfs_builder());
+ s.pattern_root->bind(TOK_PROCFS)->bind(TOK_READ)->bind(new procfs_builder());
+ s.pattern_root->bind_str(TOK_PROCFS)->bind(TOK_READ)
+ ->bind(new procfs_builder());
+ s.pattern_root->bind(TOK_PROCFS)->bind(TOK_WRITE)->bind(new procfs_builder());
+ s.pattern_root->bind_str(TOK_PROCFS)->bind(TOK_WRITE)
+ ->bind(new procfs_builder());
}