summaryrefslogtreecommitdiffstats
path: root/tapsets.cxx
diff options
context:
space:
mode:
authorDave Brolley <brolley@redhat.com>2009-05-11 14:23:59 -0400
committerDave Brolley <brolley@redhat.com>2009-05-11 14:23:59 -0400
commit7a0768a871545f8af96097de42837027922ddec1 (patch)
treeb4dc0a456e43f368af26938aad7afa84e4279d90 /tapsets.cxx
parentbbedb0a65e2f2ddee8f545e807310e7d1daed501 (diff)
parent5896cd059949413cf56678d7a7fa6c0788f576b5 (diff)
downloadsystemtap-steved-7a0768a871545f8af96097de42837027922ddec1.tar.gz
systemtap-steved-7a0768a871545f8af96097de42837027922ddec1.tar.xz
systemtap-steved-7a0768a871545f8af96097de42837027922ddec1.zip
Merge branch 'master' of git://sources.redhat.com/git/systemtap
Conflicts: tapsets.cxx
Diffstat (limited to 'tapsets.cxx')
-rw-r--r--tapsets.cxx4325
1 files changed, 208 insertions, 4117 deletions
diff --git a/tapsets.cxx b/tapsets.cxx
index 52c982ac..ec9ce3b7 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -12,6 +12,7 @@
#include "staptree.h"
#include "elaborate.h"
#include "tapsets.h"
+#include "task_finder.h"
#include "translate.h"
#include "session.h"
#include "util.h"
@@ -58,109 +59,16 @@ extern "C" {
}
-#ifdef PERFMON
-#include <perfmon/pfmlib.h>
-#include <perfmon/perfmon.h>
-#endif
-
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.
-
-template <class DP> struct generic_dpg: public derived_probe_group
-{
-protected:
- vector <DP*> probes;
-public:
- generic_dpg () {}
- void enroll (DP* probe) { probes.push_back (probe); }
-};
-
-
-
-// ------------------------------------------------------------------------
-// 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
-{
- be_t type;
- int64_t priority;
-
- be_derived_probe (probe* p, probe_point* l, be_t t, int64_t pr):
- derived_probe (p, l), type (t), priority (pr) {}
-
- void join_group (systemtap_session& s);
-
- static inline bool comp(be_derived_probe const *a,
- be_derived_probe const *b)
- {
- // This allows the BEGIN/END/ERROR probes to intermingle.
- // But that's OK - they're always treversed with a nested
- // "if (type==FOO)" conditional.
- return a->priority < b->priority;
- }
-
- bool needs_global_locks () { return false; }
- // begin/end probes don't need locks around global variables, since
- // they aren't run concurrently with any other probes
-};
-
-
-struct be_derived_probe_group: public generic_dpg<be_derived_probe>
-{
-public:
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-struct be_builder: public derived_probe_builder
-{
- be_t type;
-
- be_builder(be_t t) : type(t) {}
-
- virtual void build(systemtap_session &,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results)
- {
- int64_t 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));
- }
-};
-
-
-void
-be_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.be_derived_probes)
- s.be_derived_probes = new be_derived_probe_group ();
- s.be_derived_probes->enroll (this);
-}
// ------------------------------------------------------------------------
void
common_probe_entryfn_prologue (translator_output* o, string statestr,
string new_pp,
- bool overload_processing = true)
+ bool overload_processing)
{
o->newline() << "struct context* __restrict__ c;";
o->newline() << "#if !INTERRUPTIBLE";
@@ -174,15 +82,6 @@ common_probe_entryfn_prologue (translator_output* o, string statestr,
o->newline() << "cycles_t cycles_atstart = get_cycles ();";
o->newline() << "#endif";
-#if 0 /* XXX: PERFMON */
- o->newline() << "static struct pfarg_ctx _pfm_context;";
- o->newline() << "static void *_pfm_desc;";
- o->newline() << "static struct pfarg_pmc *_pfm_pmc_x;";
- o->newline() << "static int _pfm_num_pmc_x;";
- o->newline() << "static struct pfarg_pmd *_pfm_pmd_x;";
- o->newline() << "static int _pfm_num_pmd_x;";
-#endif
-
o->newline() << "#if INTERRUPTIBLE";
o->newline() << "preempt_disable ();";
o->newline() << "#else";
@@ -261,7 +160,7 @@ common_probe_entryfn_prologue (translator_output* o, string statestr,
void
common_probe_entryfn_epilogue (translator_output* o,
- bool overload_processing = true)
+ bool overload_processing)
{
if (overload_processing)
o->newline() << "#if defined(STP_TIMING) || defined(STP_OVERLOAD)";
@@ -347,124 +246,6 @@ common_probe_entryfn_epilogue (translator_output* o,
// ------------------------------------------------------------------------
-void
-be_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "/* ---- begin/end probes ---- */";
- s.op->newline() << "static void enter_begin_probe (void (*fn)(struct context*), const char* pp) {";
- s.op->indent(1);
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_STARTING", "pp", false);
- s.op->newline() << "(*fn) (c);";
- common_probe_entryfn_epilogue (s.op, false);
- s.op->newline(-1) << "}";
-
- s.op->newline() << "static void enter_end_probe (void (*fn)(struct context*), const char* pp) {";
- s.op->indent(1);
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_STOPPING", "pp", false);
- s.op->newline() << "(*fn) (c);";
- common_probe_entryfn_epilogue (s.op, false);
- s.op->newline(-1) << "}";
-
- s.op->newline() << "static void enter_error_probe (void (*fn)(struct context*), const char* pp) {";
- s.op->indent(1);
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_ERROR", "pp", false);
- s.op->newline() << "(*fn) (c);";
- common_probe_entryfn_epilogue (s.op, false);
- s.op->newline(-1) << "}";
-
- s.op->newline() << "static struct stap_be_probe {";
- s.op->newline(1) << "void (*ph)(struct context*);";
- s.op->newline() << "const char* pp;";
- s.op->newline() << "int type;";
- s.op->newline(-1) << "} stap_be_probes[] = {";
- s.op->indent(1);
-
- // NB: We emit the table in sorted order here, so we don't have to
- // store the priority numbers as integers and sort at run time.
-
- sort(probes.begin(), probes.end(), be_derived_probe::comp);
-
- for (unsigned i=0; i < probes.size(); i++)
- {
- s.op->newline () << "{";
- s.op->line() << " .pp="
- << lex_cast_qstring (*probes[i]->sole_location()) << ",";
- s.op->line() << " .ph=&" << probes[i]->name << ",";
- s.op->line() << " .type=" << probes[i]->type;
- s.op->line() << " },";
- }
- s.op->newline(-1) << "};";
-}
-
-void
-be_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
- s.op->newline() << "if (stp->type != " << BEGIN << ") continue;";
- s.op->newline() << "enter_begin_probe (stp->ph, stp->pp);";
- s.op->newline() << "/* rc = 0; */";
- // NB: begin probes that cause errors do not constitute registration
- // failures. An error message will probably get printed and if
- // MAXERRORS was left at 1, we'll get an stp_exit. The
- // error-handling probes will be run during the ordinary
- // unregistration phase.
- s.op->newline(-1) << "}";
-}
-
-void
-be_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
- s.op->newline() << "if (stp->type != " << END << ") continue;";
- s.op->newline() << "enter_end_probe (stp->ph, stp->pp);";
- s.op->newline(-1) << "}";
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
- s.op->newline() << "if (stp->type != " << ERROR << ") continue;";
- s.op->newline() << "enter_error_probe (stp->ph, stp->pp);";
- s.op->newline(-1) << "}";
-}
-
-
-
-// ------------------------------------------------------------------------
-// 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) {}
- never_derived_probe (probe* p, probe_point* l): derived_probe (p, l) {}
- void join_group (systemtap_session&) { /* thus no probe_group */ }
-};
-
-
-struct never_builder: public derived_probe_builder
-{
- never_builder() {}
- virtual void build(systemtap_session &,
- probe * base,
- probe_point * location,
- literal_map_t const &,
- vector<derived_probe *> & finished_results)
- {
- finished_results.push_back(new never_derived_probe(base, location));
- }
-};
-
-
-
// ------------------------------------------------------------------------
// Dwarf derived probes. "We apologize for the inconvience."
// ------------------------------------------------------------------------
@@ -1886,38 +1667,104 @@ struct dwflpp
while (dwarf_tag (die) == DW_TAG_member)
{
const char *member = dwarf_diename_integrate (die) ;
-
- if ( member != NULL )
-
- o << " " << member;
+ if ( member != NULL )
+ o << " " << member;
else
- {
- Dwarf_Die temp_die = *die;
- Dwarf_Attribute temp_attr ;
-
- if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr))
- {
- clog<<"\n Error in obtaining type attribute for "
- <<(dwarf_diename(&temp_die)?:"<anonymous>");
- return ;
- }
+ {
+ Dwarf_Die temp_die = *die;
+ Dwarf_Attribute temp_attr ;
- if ( ! dwarf_formref_die (&temp_attr,&temp_die))
- {
- clog<<"\n Error in decoding type attribute for "
- <<(dwarf_diename(&temp_die)?:"<anonymous>");
- return ;
- }
- print_members(&temp_die,o);
+ if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr))
+ {
+ clog << "\n Error in obtaining type attribute for "
+ << (dwarf_diename(&temp_die)?:"<anonymous>");
+ return;
+ }
- }
+ if (!dwarf_formref_die (&temp_attr, &temp_die))
+ {
+ clog << "\n Error in decoding type attribute for "
+ << (dwarf_diename(&temp_die)?:"<anonymous>");
+ return;
+ }
+
+ print_members(&temp_die,o);
+ }
if (dwarf_siblingof (die, &die_mem) != 0)
break;
}
}
+ bool
+ find_struct_member(const string& member,
+ Dwarf_Die *parentdie,
+ const target_symbol *e,
+ Dwarf_Die *memberdie,
+ vector<Dwarf_Attribute>& locs)
+ {
+ Dwarf_Attribute attr;
+ Dwarf_Die die = *parentdie;
+
+ switch (dwarf_child (&die, &die))
+ {
+ case 0: /* First child found. */
+ break;
+ case 1: /* No children. */
+ return false;
+ case -1: /* Error. */
+ default: /* Shouldn't happen */
+ throw semantic_error (string (dwarf_tag(&die) == DW_TAG_union_type ? "union" : "struct")
+ + string (dwarf_diename_integrate (&die) ?: "<anonymous>")
+ + string (dwarf_errmsg (-1)),
+ e->tok);
+ }
+
+ do
+ {
+ if (dwarf_tag(&die) != DW_TAG_member)
+ continue;
+
+ const char *name = dwarf_diename_integrate(&die);
+ if (name == NULL)
+ {
+ // need to recurse for anonymous structs/unions
+ Dwarf_Die subdie;
+
+ if (!dwarf_attr_integrate (&die, DW_AT_type, &attr) ||
+ !dwarf_formref_die (&attr, &subdie))
+ continue;
+
+ if (find_struct_member(member, &subdie, e, memberdie, locs))
+ goto success;
+ }
+ else if (name == member)
+ {
+ *memberdie = die;
+ goto success;
+ }
+ }
+ while (dwarf_siblingof (&die, &die) == 0);
+
+ return false;
+
+success:
+ /* As we unwind the recursion, we need to build the chain of
+ * locations that got to the final answer. */
+ if (dwarf_attr_integrate (&die, DW_AT_data_member_location, &attr))
+ locs.insert(locs.begin(), attr);
+
+ /* Union members don't usually have a location,
+ * but just use the containing union's location. */
+ else if (dwarf_tag(parentdie) != DW_TAG_union_type)
+ throw semantic_error ("no location for field '" + member
+ + "': " + string(dwarf_errmsg (-1)),
+ e->tok);
+
+ return true;
+ }
+
Dwarf_Die *
translate_components(struct obstack *pool,
struct location **tail,
@@ -1928,8 +1775,6 @@ struct dwflpp
Dwarf_Attribute *attr_mem)
{
Dwarf_Die *die = NULL;
- Dwarf_Die struct_die;
- Dwarf_Attribute temp_attr;
unsigned i = 0;
@@ -1939,11 +1784,6 @@ struct dwflpp
if (e->components.empty())
return die_mem;
- static unsigned int func_call_level ;
- static unsigned int dwarf_error_flag ; // indicates current error is dwarf error
- static unsigned int dwarf_error_count ; // keeps track of no of dwarf errors
- static semantic_error saved_dwarf_error("");
-
while (i < e->components.size())
{
/* XXX: This would be desirable, but we don't get the target_symbol token,
@@ -1990,7 +1830,6 @@ struct dwflpp
case DW_TAG_structure_type:
case DW_TAG_union_type:
- struct_die = *die;
if (dwarf_hasattr(die, DW_AT_declaration))
{
Dwarf_Die *tmpdie = dwflpp::declaration_resolve(dwarf_diename(die));
@@ -2000,93 +1839,27 @@ struct dwflpp
e->tok);
*die_mem = *tmpdie;
}
- switch (dwarf_child (die, die_mem))
- {
- case 1: /* No children. */
- return NULL;
- case -1: /* Error. */
- default: /* Shouldn't happen */
- throw semantic_error (string (typetag == DW_TAG_union_type ? "union" : "struct")
- + string (dwarf_diename_integrate (die) ?: "<anonymous>")
- + string (dwarf_errmsg (-1)),
- e->tok);
- break;
-
- case 0:
- break;
- }
-
- while (dwarf_tag (die) != DW_TAG_member
- || ({ const char *member = dwarf_diename_integrate (die);
- member == NULL || string(member) != e->components[i].second; }))
- {
- if ( dwarf_diename (die) == NULL ) // handling Anonymous structs/unions
- {
- Dwarf_Die temp_die = *die;
- Dwarf_Die temp_die_2;
-
- try
- {
- if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr))
- {
- dwarf_error_flag ++ ;
- dwarf_error_count ++;
- throw semantic_error(" Error in obtaining type attribute for "+ string(dwarf_diename(&temp_die)?:"<anonymous>"), e->tok);
- }
-
- if ( !dwarf_formref_die (&temp_attr, &temp_die))
- {
- dwarf_error_flag ++ ;
- dwarf_error_count ++;
- throw semantic_error(" Error in decoding DW_AT_type attribute for " + string(dwarf_diename(&temp_die)?:"<anonymous>"), e->tok);
- }
-
- func_call_level ++ ;
-
- Dwarf_Die *result_die = translate_components(pool, tail, pc, e, &temp_die, &temp_die_2, &temp_attr);
-
- func_call_level -- ;
-
- if (result_die != NULL)
- {
- memcpy(die_mem, &temp_die_2, sizeof(Dwarf_Die));
- memcpy(attr_mem, &temp_attr, sizeof(Dwarf_Attribute));
- return die_mem;
- }
- }
- catch (const semantic_error& e)
- {
- if ( !dwarf_error_flag ) //not a dwarf error
- throw;
- else
- {
- dwarf_error_flag = 0 ;
- saved_dwarf_error = e ;
- }
- }
- }
- if (dwarf_siblingof (die, die_mem) != 0)
- {
- if ( func_call_level == 0 && dwarf_error_count ) // this is parent call & a dwarf error has been reported in a branch somewhere
- throw semantic_error( saved_dwarf_error );
- else
- return NULL;
- }
- }
- if (dwarf_attr_integrate (die, DW_AT_data_member_location,
- attr_mem) == NULL)
{
- /* Union members don't usually have a location,
- but just use the containing union's location. */
- if (typetag != DW_TAG_union_type)
- throw semantic_error ("no location for field '"
- + e->components[i].second
- + "' :" + string(dwarf_errmsg (-1)),
- e->tok);
+ vector<Dwarf_Attribute> locs;
+ if (!find_struct_member(e->components[i].second, die, e, die, locs))
+ {
+ string alternatives;
+ stringstream members;
+ print_members(die, members);
+ if (members.str().size() != 0)
+ alternatives = " (alternatives:" + members.str();
+ throw semantic_error("unable to find member '" +
+ e->components[i].second + "' for struct "
+ + string(dwarf_diename_integrate(die) ?: "<unknown>")
+ + alternatives,
+ e->tok);
+ }
+
+ for (unsigned j = 0; j < locs.size(); ++j)
+ translate_location (pool, &locs[j], pc, NULL, tail, e);
}
- else
- translate_location (pool, attr_mem, pc, NULL, tail, e);
+
++i;
break;
@@ -2368,17 +2141,6 @@ struct dwflpp
Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem);
die = translate_components (&pool, &tail, pc, e,
die, &die_mem, &attr_mem);
- if(!die)
- {
- die = dwarf_formref_die (&attr_mem, &die_mem);
- stringstream alternatives;
- if (die != NULL)
- print_members(die,alternatives);
- throw semantic_error("unable to find local '" + local + "'"
- + " near pc " + lex_cast_hex<string>(pc)
- + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")),
- e->tok);
- }
/* Translate the assignment part, either
x = $foo->bar->baz[NN]
@@ -2456,22 +2218,6 @@ struct dwflpp
Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem);
die = translate_components (&pool, &tail, pc, e,
die, &die_mem, &attr_mem);
- if(!die)
- {
- die = dwarf_formref_die (&attr_mem, &die_mem);
- stringstream alternatives;
- if (die != NULL)
- print_members(die,alternatives);
- throw semantic_error("unable to find return value"
- " near pc " + lex_cast_hex<string>(pc)
- + " for "
- + string(dwarf_diename(scope_die) ?: "<unknown>")
- + "(" + string(dwarf_diename(cu) ?: "<unknown>")
- + ")"
- + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")),
- e->tok);
- }
-
/* Translate the assignment part, either
x = $return->bar->baz[NN]
@@ -2515,17 +2261,6 @@ struct dwflpp
Dwarf_Die die_mem, *die = NULL;
die = translate_components (&pool, &tail, 0, e,
type_die, &die_mem, &attr_mem);
- if(!die)
- {
- die = dwarf_formref_die (&attr_mem, &die_mem);
- stringstream alternatives;
- print_members(die ?: type_die, alternatives);
- throw semantic_error("unable to find member for struct "
- + string(dwarf_diename(die ?: type_die) ?: "<unknown>")
- + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")),
- e->tok);
- }
-
/* Translate the assignment part, either
x = (THIS->pointer)->bar->baz[NN]
@@ -2638,41 +2373,6 @@ struct uprobe_derived_probe: public derived_probe
void join_group (systemtap_session& s);
};
-struct kprobe_derived_probe: public derived_probe
-{
- kprobe_derived_probe (probe *base,
- probe_point *location,
- const string& name,
- int64_t stmt_addr,
- bool has_return,
- bool has_statement,
- bool has_maxactive,
- long maxactive_val
- );
- string symbol_name;
- Dwarf_Addr addr;
- bool has_return;
- bool has_statement;
- bool has_maxactive;
- long maxactive_val;
- bool access_var;
- void printsig (std::ostream &o) const;
- void join_group (systemtap_session& s);
-};
-
-struct kprobe_derived_probe_group: public derived_probe_group
-{
-private:
- multimap<string,kprobe_derived_probe*> probes_by_module;
- typedef multimap<string,kprobe_derived_probe*>::iterator p_b_m_iterator;
-
-public:
- void enroll (kprobe_derived_probe* probe);
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
struct dwarf_derived_probe_group: public derived_probe_group
{
private:
@@ -4479,15 +4179,6 @@ dwflpp::query_modules(base_query *q)
iterate_over_modules(&query_module, q);
}
-struct var_expanding_visitor: public update_visitor
-{
- static unsigned tick;
- stack<functioncall**> target_symbol_setter_functioncalls;
-
- var_expanding_visitor() {}
- void visit_assignment (assignment* e);
-};
-
struct dwarf_var_expanding_visitor: public var_expanding_visitor
{
@@ -5087,13 +4778,13 @@ dwarf_var_expanding_visitor::visit_cast_op (cast_op *e)
struct dwarf_cast_query : public base_query
{
- const cast_op& e;
+ cast_op& e;
const bool lvalue;
exp_type& pe_type;
string& code;
- dwarf_cast_query(dwflpp& dw, const string& module, const cast_op& e,
+ dwarf_cast_query(dwflpp& dw, const string& module, cast_op& e,
bool lvalue, exp_type& pe_type, string& code):
base_query(dw, module), e(e), lvalue(lvalue),
pe_type(pe_type), code(code) {}
@@ -5131,11 +4822,15 @@ dwarf_cast_query::handle_query_cu(Dwarf_Die * cudie)
code = dw.literal_stmt_for_pointer (type_die, &e,
lvalue, pe_type);
}
- catch (const semantic_error& e)
+ catch (const semantic_error& er)
{
- // XXX might be better to save the error
- // and try again in another CU
- sess.print_error (e);
+ // XXX might be better to try again in another CU
+ // NB: we can have multiple errors, since a @cast
+ // may be expanded in several different contexts:
+ // function ("*") { @cast(...) }
+ semantic_error* new_er = new semantic_error(er);
+ new_er->chain = e.saved_conversion_error;
+ e.saved_conversion_error = new_er;
}
return DWARF_CB_ABORT;
}
@@ -5284,17 +4979,9 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
if (code.empty())
{
- // We generate an error message, and pass the unresolved
- // cast_op to the next pass. We hope that this value ends
- // up not being referenced after all, so it can be optimized out
- // quietly.
- string msg = "type definition '" + e->type + "' not found";
- semantic_error* er = new semantic_error (msg, e->tok);
- // NB: we can have multiple errors, since a @cast
- // may be expanded in several different contexts:
- // function ("*") { @cast(...) }
- er->chain = e->saved_conversion_error;
- e->saved_conversion_error = er;
+ // We pass the unresolved cast_op to the next pass, and hope
+ // that this value ends up not being referenced after all, so
+ // it can be optimized out quietly.
provide (e);
return;
}
@@ -5592,24 +5279,6 @@ dwarf_derived_probe_group::enroll (dwarf_derived_probe* p)
// sequentially.
}
-/*
-void
-dwarf_derived_probe_group::enroll (kprobe_derived_probe* p)
-{
- dwarf_derived_probe *dw_probe = new dwarf_derived_probe (p->symbol_name,
- "",0,
- p->module_name,
- p->section_name,
- 0,0,
- p->q,NULL);
- 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.
-}
-*/
-
void
dwarf_derived_probe_group::emit_module_decls (systemtap_session& s)
{
@@ -5953,6 +5622,9 @@ dwarf_builder::build(systemtap_session & sess,
dw = user_dw[module_name];
}
+ if (sess.verbose > 3)
+ clog << "dwarf_builder::build for " << module_name << endl;
+
if (((probe_point::component*)(location->components[1]))->functor == TOK_MARK)
{
enum probe_types
@@ -5964,9 +5636,13 @@ dwarf_builder::build(systemtap_session & sess,
int probe_type = dwarf_no_probes;
string probe_name = (char*) location->components[1]->arg->tok->content.c_str();
+ if (sess.verbose > 3)
+ clog << "TOK_MARK: " << probe_name << endl;
+
__uint64_t probe_arg = 0;
Dwarf_Addr bias;
- Elf* elf = dwfl_module_getelf (dw->module, &bias);
+ Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (dw->module, &bias))
+ ?: dwfl_module_getelf (dw->module, &bias));
size_t shstrndx;
Elf_Scn *probe_scn = NULL;
@@ -5987,18 +5663,31 @@ dwarf_builder::build(systemtap_session & sess,
}
}
+ // We got our .probes section, extract data.
if (probe_type == probes_and_dwarf)
{
+ if (sess.verbose > 3)
+ clog << "probe_type == probes_and_dwarf, use statement addr" << endl;
+
Elf_Data *pdata = elf_getdata_rawchunk (elf, shdr->sh_offset, shdr->sh_size, ELF_T_BYTE);
assert (pdata != NULL);
size_t probe_scn_offset = 0;
size_t probe_scn_addr = shdr->sh_addr;
+ if (sess.verbose > 4)
+ clog << "got .probes elf scn_addr@0x" << probe_scn_addr << dec
+ << ", size: " << pdata->d_size << endl;
while (probe_scn_offset < pdata->d_size)
{
const int stap_sentinel = 0x31425250;
probe_type = *((int*)((char*)pdata->d_buf + probe_scn_offset));
if (probe_type != stap_sentinel)
{
+ // Unless this is a mangled .probes section, this happens
+ // because the name of the probe comes first, followed by
+ // the sentinel.
+ if (sess.verbose > 5)
+ clog << "got unknown probe_type: 0x" << hex << probe_type
+ << dec << endl;
probe_scn_offset += sizeof(int);
continue;
}
@@ -6011,6 +5700,10 @@ dwarf_builder::build(systemtap_session & sess,
if (probe_scn_offset % (sizeof(__uint64_t)))
probe_scn_offset += sizeof(__uint64_t) - (probe_scn_offset % sizeof(__uint64_t));
probe_arg = *((__uint64_t*)((char*)pdata->d_buf + probe_scn_offset));
+ if (sess.verbose > 4)
+ clog << "saw .probes " << probe_name
+ << "@0x" << hex << probe_arg << dec << endl;
+
if (probe_scn_offset % (sizeof(__uint64_t)*2))
probe_scn_offset = (probe_scn_offset + sizeof(__uint64_t)*2) - (probe_scn_offset % (sizeof(__uint64_t)*2));
if ((strcmp (location->components[1]->arg->tok->content.c_str(),
@@ -6020,6 +5713,9 @@ dwarf_builder::build(systemtap_session & sess,
(probe_name.c_str(),
location->components[1]->arg->tok->content.c_str())))
{
+ if (sess.verbose > 3)
+ clog << "found probe_name" << probe_name << " at 0x"
+ << hex << probe_arg << dec << endl;
}
else
continue;
@@ -6028,6 +5724,10 @@ dwarf_builder::build(systemtap_session & sess,
location->components[1]->arg = new literal_number((long)probe_arg);
location->components[1]->arg->tok = sv_tok;
((literal_map_t&)parameters)[TOK_STATEMENT] = location->components[1]->arg;
+
+ if (sess.verbose > 3)
+ clog << "probe_type == probes_and_dwarf, use statement addr: 0x"
+ << hex << probe_arg << dec << endl;
dwarf_query q(sess, base, location, *dw, parameters, finished_results);
q.has_mark = true;
@@ -6050,8 +5750,15 @@ dwarf_builder::build(systemtap_session & sess,
location->components[2]->arg = new literal_string("_stapprobe1_" + probe_name);
((literal_map_t&)parameters).erase(TOK_MARK);
((literal_map_t&)parameters).insert(pair<string,literal*>(TOK_LABEL, location->components[2]->arg));
+
+ if (sess.verbose > 3)
+ clog << "probe_type == dwarf_no_probes, use label name: "
+ << "_stapprobe1_" << probe_name << endl;
}
+ else if (sess.verbose > 3)
+ clog << "probe_type == probes_no_dwarf" << endl;
+
dw->module = 0;
}
@@ -6437,1387 +6144,6 @@ module_info::~module_info()
delete sym_table;
}
-// Helper function to emit vma tracker callbacks.
-static void
-emit_vma_callback_probe_decl (systemtap_session& s,
- string path,
- int64_t pid)
-{
- s.op->newline() << "{";
- if (pid == 0)
- {
- 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() << " .mmap_callback=&_stp_tf_mmap_cb,";
- s.op->line() << " .munmap_callback=&_stp_tf_munmap_cb,";
- s.op->line() << " .mprotect_callback=NULL,";
- s.op->line() << " },";
-}
-
-// ------------------------------------------------------------------------
-// task_finder derived 'probes': These don't really exist. The whole
-// purpose of the task_finder_derived_probe_group is to make sure that
-// stap_start_task_finder()/stap_stop_task_finder() get called only
-// once and in the right place.
-// ------------------------------------------------------------------------
-
-struct task_finder_derived_probe: public derived_probe
-{
- // Dummy constructor for gcc 3.4 compatibility
- task_finder_derived_probe (): derived_probe (0) { assert(0); }
-};
-
-
-struct task_finder_derived_probe_group: public generic_dpg<task_finder_derived_probe>
-{
-public:
- static void create_session_group (systemtap_session& s);
-
- void emit_module_decls (systemtap_session& ) { }
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-
-void
-task_finder_derived_probe_group::create_session_group (systemtap_session& s)
-{
- if (! s.task_finder_derived_probes)
- s.task_finder_derived_probes = new task_finder_derived_probe_group();
-}
-
-
-void
-task_finder_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- s.op->newline();
- s.op->newline() << "/* ---- task finder ---- */";
- s.op->newline() << "rc = stap_start_task_finder();";
-
- s.op->newline() << "if (rc) {";
- s.op->newline(1) << "stap_stop_task_finder();";
- s.op->newline(-1) << "}";
-}
-
-
-void
-task_finder_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- s.op->newline();
- s.op->newline() << "/* ---- task finder ---- */";
- s.op->newline() << "stap_stop_task_finder();";
-}
-
-// ------------------------------------------------------------------------
-// itrace user-space probes
-// ------------------------------------------------------------------------
-
-
-static string TOK_INSN("insn");
-static string TOK_BLOCK("block");
-
-struct itrace_derived_probe: public derived_probe
-{
- bool has_path;
- string path;
- int64_t pid;
- int single_step;
-
- itrace_derived_probe (systemtap_session &s, probe* p, probe_point* l,
- bool hp, string &pn, int64_t pd, int ss
- );
- void join_group (systemtap_session& s);
-};
-
-
-struct itrace_derived_probe_group: public generic_dpg<itrace_derived_probe>
-{
-private:
- map<string, vector<itrace_derived_probe*> > probes_by_path;
- typedef map<string, vector<itrace_derived_probe*> >::iterator p_b_path_iterator;
- map<int64_t, vector<itrace_derived_probe*> > probes_by_pid;
- typedef map<int64_t, vector<itrace_derived_probe*> >::iterator p_b_pid_iterator;
- unsigned num_probes;
-
- void emit_probe_decl (systemtap_session& s, itrace_derived_probe *p);
-
-public:
- itrace_derived_probe_group(): num_probes(0) { }
-
- void enroll (itrace_derived_probe* probe);
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-
-itrace_derived_probe::itrace_derived_probe (systemtap_session &s,
- probe* p, probe_point* l,
- bool hp, string &pn, int64_t pd,
- int ss
- ):
- derived_probe(p, l), has_path(hp), path(pn), pid(pd), single_step(ss)
-{
-}
-
-
-void
-itrace_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.itrace_derived_probes)
- s.itrace_derived_probes = new itrace_derived_probe_group ();
-
- s.itrace_derived_probes->enroll (this);
-
- task_finder_derived_probe_group::create_session_group (s);
-}
-
-struct itrace_builder: public derived_probe_builder
-{
- itrace_builder() {}
- virtual void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- std::map<std::string, literal *> const & parameters,
- vector<derived_probe *> & finished_results)
- {
- string path;
- int64_t pid = 0;
- int single_step;
-
- bool has_path = get_param (parameters, TOK_PROCESS, path);
- bool has_pid = get_param (parameters, TOK_PROCESS, pid);
- // XXX: PR 6445 needs !has_path && !has_pid support
- assert (has_path || has_pid);
-
- single_step = ! has_null_param (parameters, TOK_BLOCK);
-
- // If we have a path, we need to validate it.
- if (has_path)
- path = find_executable (path);
-
- finished_results.push_back(new itrace_derived_probe(sess, base, location,
- has_path, path, pid,
- single_step
- ));
- }
-};
-
-
-void
-itrace_derived_probe_group::enroll (itrace_derived_probe* p)
-{
- if (p->has_path)
- probes_by_path[p->path].push_back(p);
- else
- probes_by_pid[p->pid].push_back(p);
- num_probes++;
-
- // XXX: multiple exec probes (for instance) for the same path (or
- // pid) should all share a itrace report function, and have their
- // handlers executed sequentially.
-}
-
-
-void
-itrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
- itrace_derived_probe *p)
-{
- s.op->newline() << "{";
- s.op->line() << " .tgt={";
-
- if (p->has_path)
- {
- s.op->line() << " .pathname=\"" << p->path << "\",";
- s.op->line() << " .pid=0,";
- }
- else
- {
- s.op->line() << " .pathname=NULL,";
- s.op->line() << " .pid=" << p->pid << ",";
- }
-
- s.op->line() << " .callback=&_stp_itrace_probe_cb,";
- s.op->line() << " },";
- s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ",";
- s.op->line() << " .single_step=" << p->single_step << ",";
- s.op->line() << " .ph=&" << p->name << ",";
-
- s.op->line() << " },";
-}
-
-
-void
-itrace_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes_by_path.empty() && probes_by_pid.empty())
- return;
-
- s.op->newline();
- s.op->newline() << "/* ---- itrace probes ---- */";
-
- s.op->newline() << "struct stap_itrace_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() << "int single_step;";
- s.op->newline(-1) << "};";
- s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data);";
- s.op->newline() << "#include \"itrace.c\"";
-
- // output routine to call itrace probe
- s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data) {";
- s.op->indent(1);
-
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp");
- s.op->newline() << "c->regs = regs;";
- s.op->newline() << "c->data = data;";
-
- // call probe function
- s.op->newline() << "(*p->ph) (c);";
- common_probe_entryfn_epilogue (s.op);
-
- s.op->newline() << "return;";
- s.op->newline(-1) << "}";
-
- // Output task finder callback routine that gets called for all
- // itrace probe types.
- s.op->newline() << "static int _stp_itrace_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
- s.op->indent(1);
- s.op->newline() << "int rc = 0;";
- s.op->newline() << "struct stap_itrace_probe *p = container_of(tgt, struct stap_itrace_probe, tgt);";
-
- s.op->newline() << "if (register_p) ";
- s.op->indent(1);
-
- s.op->newline() << "rc = usr_itrace_init(p->single_step, tsk->pid, p);";
- s.op->newline(-1) << "else";
- s.op->newline(1) << "remove_usr_itrace_info(find_itrace_info(p->tgt.pid));";
- s.op->newline(-1) << "return rc;";
- s.op->newline(-1) << "}";
-
- // Emit vma callbacks.
- s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
- s.op->newline() << "static struct stap_task_finder_target stap_itrace_vmcbs[] = {";
- s.op->indent(1);
- if (! probes_by_path.empty())
- {
- for (p_b_path_iterator it = probes_by_path.begin();
- it != probes_by_path.end(); it++)
- emit_vma_callback_probe_decl (s, it->first, (int64_t)0);
- }
- if (! probes_by_pid.empty())
- {
- for (p_b_pid_iterator it = probes_by_pid.begin();
- it != probes_by_pid.end(); it++)
- emit_vma_callback_probe_decl (s, "", it->first);
- }
- s.op->newline(-1) << "};";
- s.op->newline() << "#endif";
-
- s.op->newline() << "static struct stap_itrace_probe stap_itrace_probes[] = {";
- s.op->indent(1);
-
- // Set up 'process(PATH)' probes
- if (! probes_by_path.empty())
- {
- for (p_b_path_iterator it = probes_by_path.begin();
- it != probes_by_path.end(); it++)
- {
- for (unsigned i = 0; i < it->second.size(); i++)
- {
- itrace_derived_probe *p = it->second[i];
- emit_probe_decl(s, p);
- }
- }
- }
-
- // Set up 'process(PID)' probes
- if (! probes_by_pid.empty())
- {
- for (p_b_pid_iterator it = probes_by_pid.begin();
- it != probes_by_pid.end(); it++)
- {
- for (unsigned i = 0; i < it->second.size(); i++)
- {
- itrace_derived_probe *p = it->second[i];
- emit_probe_decl(s, p);
- }
- }
- }
- s.op->newline(-1) << "};";
-}
-
-
-void
-itrace_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes_by_path.empty() && probes_by_pid.empty())
- return;
-
- s.op->newline();
- s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
- s.op->newline() << "_stp_sym_init();";
- s.op->newline() << "/* ---- itrace vma callbacks ---- */";
- s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_itrace_vmcbs); i++) {";
- s.op->indent(1);
- s.op->newline() << "struct stap_task_finder_target *r = &stap_itrace_vmcbs[i];";
- s.op->newline() << "rc = stap_register_task_finder_target(r);";
- s.op->newline(-1) << "}";
- s.op->newline() << "#endif";
-
- s.op->newline();
- s.op->newline() << "/* ---- itrace probes ---- */";
-
- s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {";
- s.op->indent(1);
- s.op->newline() << "struct stap_itrace_probe *p = &stap_itrace_probes[i];";
-
- // 'arch_has_single_step' needs to be defined for either single step mode
- // or branch mode.
- s.op->newline() << "if (!arch_has_single_step()) {";
- s.op->indent(1);
- s.op->newline() << "_stp_error (\"insn probe init: arch does not support step mode\");";
- s.op->newline() << "rc = -EPERM;";
- s.op->newline() << "break;";
- s.op->newline(-1) << "}";
- s.op->newline() << "if (!p->single_step && !arch_has_block_step()) {";
- s.op->indent(1);
- s.op->newline() << "_stp_error (\"insn probe init: arch does not support block step mode\");";
- s.op->newline() << "rc = -EPERM;";
- s.op->newline() << "break;";
- s.op->newline(-1) << "}";
-
- s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
- s.op->newline(-1) << "}";
-}
-
-
-void
-itrace_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes_by_path.empty() && probes_by_pid.empty()) return;
- s.op->newline();
- s.op->newline() << "/* ---- itrace probes ---- */";
- s.op->newline() << "cleanup_usr_itrace();";
-}
-
-// ------------------------------------------------------------------------
-// utrace user-space probes
-// ------------------------------------------------------------------------
-
-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_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
-};
-
-struct utrace_derived_probe: public derived_probe
-{
- bool has_path;
- string path;
- int64_t pid;
- enum utrace_derived_probe_flags flags;
- bool target_symbol_seen;
-
- utrace_derived_probe (systemtap_session &s, probe* p, probe_point* l,
- bool hp, string &pn, int64_t pd,
- enum utrace_derived_probe_flags f);
- void join_group (systemtap_session& s);
-};
-
-
-struct utrace_derived_probe_group: public generic_dpg<utrace_derived_probe>
-{
-private:
- map<string, vector<utrace_derived_probe*> > probes_by_path;
- typedef map<string, vector<utrace_derived_probe*> >::iterator p_b_path_iterator;
- map<int64_t, vector<utrace_derived_probe*> > probes_by_pid;
- typedef map<int64_t, vector<utrace_derived_probe*> >::iterator p_b_pid_iterator;
- unsigned num_probes;
- bool flags_seen[UDPF_NFLAGS];
-
- void emit_probe_decl (systemtap_session& s, utrace_derived_probe *p);
-
-public:
- utrace_derived_probe_group(): num_probes(0), flags_seen() { }
-
- void enroll (utrace_derived_probe* probe);
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-
-struct utrace_var_expanding_visitor: public var_expanding_visitor
-{
- utrace_var_expanding_visitor(systemtap_session& s, probe_point* l,
- const string& pn,
- enum utrace_derived_probe_flags f):
- sess (s), base_loc (l), probe_name (pn), flags (f),
- target_symbol_seen (false), add_block(NULL), add_probe(NULL) {}
-
- systemtap_session& sess;
- probe_point* base_loc;
- string probe_name;
- enum utrace_derived_probe_flags flags;
- bool target_symbol_seen;
- block *add_block;
- probe *add_probe;
- std::map<std::string, symbol *> return_ts_map;
-
- void visit_target_symbol_arg (target_symbol* e);
- void visit_target_symbol_context (target_symbol* e);
- void visit_target_symbol_cached (target_symbol* e);
- void visit_target_symbol (target_symbol* e);
-};
-
-
-
-utrace_derived_probe::utrace_derived_probe (systemtap_session &s,
- probe* p, probe_point* l,
- bool hp, string &pn, int64_t pd,
- enum utrace_derived_probe_flags f):
- derived_probe (p, new probe_point (*l) /* .components soon rewritten */ ),
- has_path(hp), path(pn), pid(pd), flags(f),
- target_symbol_seen(false)
-{
- // Expand local variables in the probe body
- utrace_var_expanding_visitor v (s, l, name, flags);
- this->body = v.require (this->body);
- target_symbol_seen = v.target_symbol_seen;
-
- // If during target-variable-expanding the probe, we added a new block
- // of code, add it to the start of the probe.
- if (v.add_block)
- this->body = new block(v.add_block, this->body);
- // If when target-variable-expanding the probe, we added a new
- // probe, add it in a new file to the list of files to be processed.
- if (v.add_probe)
- {
- stapfile *f = new stapfile;
- f->probes.push_back(v.add_probe);
- s.files.push_back(f);
- }
-
- // Reset the sole element of the "locations" vector as a
- // "reverse-engineered" form of the incoming (q.base_loc) probe
- // point. This allows a user to see what program etc.
- // number any particular match of the wildcards.
-
- vector<probe_point::component*> comps;
- if (hp)
- comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(path)));
- else if (pid != 0)
- comps.push_back (new probe_point::component(TOK_PROCESS, new literal_number(pid)));
- else
- comps.push_back (new probe_point::component(TOK_PROCESS));
-
- switch (flags)
- {
- case UDPF_THREAD_BEGIN:
- comps.push_back (new probe_point::component(TOK_THREAD));
- comps.push_back (new probe_point::component(TOK_BEGIN));
- break;
- case UDPF_THREAD_END:
- comps.push_back (new probe_point::component(TOK_THREAD));
- comps.push_back (new probe_point::component(TOK_END));
- break;
- case UDPF_SYSCALL:
- comps.push_back (new probe_point::component(TOK_SYSCALL));
- break;
- case UDPF_SYSCALL_RETURN:
- comps.push_back (new probe_point::component(TOK_SYSCALL));
- comps.push_back (new probe_point::component(TOK_RETURN));
- break;
- case UDPF_BEGIN:
- comps.push_back (new probe_point::component(TOK_BEGIN));
- break;
- case UDPF_END:
- comps.push_back (new probe_point::component(TOK_END));
- break;
- default:
- assert (0);
- }
-
- // Overwrite it.
- this->sole_location()->components = comps;
-}
-
-
-void
-utrace_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.utrace_derived_probes)
- {
- s.utrace_derived_probes = new utrace_derived_probe_group ();
- }
- s.utrace_derived_probes->enroll (this);
-
- task_finder_derived_probe_group::create_session_group (s);
-}
-
-
-void
-utrace_var_expanding_visitor::visit_target_symbol_cached (target_symbol* e)
-{
- // Get the full name of the target symbol.
- stringstream ts_name_stream;
- e->print(ts_name_stream);
- string ts_name = ts_name_stream.str();
-
- // Check and make sure we haven't already seen this target
- // variable in this return probe. If we have, just return our
- // last replacement.
- map<string, symbol *>::iterator i = return_ts_map.find(ts_name);
- if (i != return_ts_map.end())
- {
- provide (i->second);
- return;
- }
-
- // We've got to do several things here to handle target
- // variables in return probes.
-
- // (1) Synthesize a global array which is the cache of the
- // target variable value. We don't need a nesting level counter
- // like the dwarf_var_expanding_visitor::visit_target_symbol()
- // does since a particular thread can only be in one system
- // calls at a time. The array will look like this:
- //
- // _utrace_tvar_{name}_{num}
- string aname = (string("_utrace_tvar_")
- + e->base_name.substr(1)
- + "_" + lex_cast<string>(tick++));
- vardecl* vd = new vardecl;
- vd->name = aname;
- vd->tok = e->tok;
- sess.globals.push_back (vd);
-
- // (2) Create a new code block we're going to insert at the
- // beginning of this probe to get the cached value into a
- // temporary variable. We'll replace the target variable
- // reference with the temporary variable reference. The code
- // will look like this:
- //
- // _utrace_tvar_tid = tid()
- // _utrace_tvar_{name}_{num}_tmp
- // = _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
- // delete _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
-
- // (2a) Synthesize the tid temporary expression, which will look
- // like this:
- //
- // _utrace_tvar_tid = tid()
- symbol* tidsym = new symbol;
- tidsym->name = string("_utrace_tvar_tid");
- tidsym->tok = e->tok;
-
- if (add_block == NULL)
- {
- add_block = new block;
- add_block->tok = e->tok;
-
- // Synthesize a functioncall to grab the thread id.
- functioncall* fc = new functioncall;
- fc->tok = e->tok;
- fc->function = string("tid");
-
- // Assign the tid to '_utrace_tvar_tid'.
- assignment* a = new assignment;
- a->tok = e->tok;
- a->op = "=";
- a->left = tidsym;
- a->right = fc;
-
- expr_statement* es = new expr_statement;
- es->tok = e->tok;
- es->value = a;
- add_block->statements.push_back (es);
- }
-
- // (2b) Synthesize an array reference and assign it to a
- // temporary variable (that we'll use as replacement for the
- // target variable reference). It will look like this:
- //
- // _utrace_tvar_{name}_{num}_tmp
- // = _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
-
- arrayindex* ai_tvar = new arrayindex;
- ai_tvar->tok = e->tok;
-
- symbol* sym = new symbol;
- sym->name = aname;
- sym->tok = e->tok;
- ai_tvar->base = sym;
-
- ai_tvar->indexes.push_back(tidsym);
-
- symbol* tmpsym = new symbol;
- tmpsym->name = aname + "_tmp";
- tmpsym->tok = e->tok;
-
- assignment* a = new assignment;
- a->tok = e->tok;
- a->op = "=";
- a->left = tmpsym;
- a->right = ai_tvar;
-
- expr_statement* es = new expr_statement;
- es->tok = e->tok;
- es->value = a;
-
- add_block->statements.push_back (es);
-
- // (2c) Delete the array value. It will look like this:
- //
- // delete _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
-
- delete_statement* ds = new delete_statement;
- ds->tok = e->tok;
- ds->value = ai_tvar;
- add_block->statements.push_back (ds);
-
- // (3) We need an entry probe that saves the value for us in the
- // global array we created. Create the entry probe, which will
- // look like this:
- //
- // probe process(PATH_OR_PID).syscall {
- // _utrace_tvar_tid = tid()
- // _utrace_tvar_{name}_{num}[_utrace_tvar_tid] = ${param}
- // }
- //
- // Why the temporary for tid()? If we end up caching more
- // than one target variable, we can reuse the temporary instead
- // of calling tid() multiple times.
-
- if (add_probe == NULL)
- {
- add_probe = new probe;
- add_probe->tok = e->tok;
-
- // We need the name of the current probe point, minus the
- // ".return". Create a new probe point, copying all the
- // components, stopping when we see the ".return"
- // component.
- probe_point* pp = new probe_point;
- for (unsigned c = 0; c < base_loc->components.size(); c++)
- {
- if (base_loc->components[c]->functor == "return")
- break;
- else
- pp->components.push_back(base_loc->components[c]);
- }
- pp->tok = e->tok;
- pp->optional = base_loc->optional;
- add_probe->locations.push_back(pp);
-
- add_probe->body = new block;
- add_probe->body->tok = e->tok;
-
- // Synthesize a functioncall to grab the thread id.
- functioncall* fc = new functioncall;
- fc->tok = e->tok;
- fc->function = string("tid");
-
- // Assign the tid to '_utrace_tvar_tid'.
- assignment* a = new assignment;
- a->tok = e->tok;
- a->op = "=";
- a->left = tidsym;
- a->right = fc;
-
- expr_statement* es = new expr_statement;
- es->tok = e->tok;
- es->value = a;
- add_probe->body = new block(add_probe->body, es);
-
- vardecl* vd = new vardecl;
- vd->tok = e->tok;
- vd->name = tidsym->name;
- vd->type = pe_long;
- vd->set_arity(0);
- add_probe->locals.push_back(vd);
- }
-
- // Save the value, like this:
- //
- // _utrace_tvar_{name}_{num}[_utrace_tvar_tid] = ${param}
- a = new assignment;
- a->tok = e->tok;
- a->op = "=";
- a->left = ai_tvar;
- a->right = e;
-
- es = new expr_statement;
- es->tok = e->tok;
- es->value = a;
-
- add_probe->body = new block(add_probe->body, es);
-
- // (4) Provide the '_utrace_tvar_{name}_{num}_tmp' variable to
- // our parent so it can be used as a substitute for the target
- // symbol.
- provide (tmpsym);
-
- // (5) Remember this replacement since we might be able to reuse
- // it later if the same return probe references this target
- // symbol again.
- return_ts_map[ts_name] = tmpsym;
- return;
-}
-
-
-void
-utrace_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
-{
- string argnum_s = e->base_name.substr(4,e->base_name.length()-4);
- int argnum = lex_cast<int>(argnum_s);
-
- if (flags != UDPF_SYSCALL)
- throw semantic_error ("only \"process(PATH_OR_PID).syscall\" support $argN.", e->tok);
-
- if (e->components.size() > 0)
- {
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("utrace target variable '$argN' may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("utrace target variable '$argN' may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid use of utrace target variable '$argN'",
- e->tok);
- break;
- }
- }
-
- // FIXME: max argnument number should not be hardcoded.
- if (argnum < 1 || argnum > 6)
- throw semantic_error ("invalid syscall argument number (1-6)", e->tok);
-
- bool lvalue = is_active_lvalue(e);
- if (lvalue)
- throw semantic_error("utrace '$argN' variable is read-only", e->tok);
-
- // Remember that we've seen a target variable.
- target_symbol_seen = true;
-
- // We're going to substitute a synthesized '_utrace_syscall_arg'
- // function call for the '$argN' reference.
- functioncall* n = new functioncall;
- n->tok = e->tok;
- n->function = "_utrace_syscall_arg";
- n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
-
- literal_number *num = new literal_number(argnum - 1);
- num->tok = e->tok;
- n->args.push_back(num);
-
- provide (n);
-}
-
-void
-utrace_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
-{
- string sname = e->base_name;
-
- if (e->components.size() > 0)
- {
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("utrace target variable '" + sname + "' may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("utrace target variable '" + sname + "' may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid use of utrace target variable '" + sname + "'",
- e->tok);
- break;
- }
- }
-
- bool lvalue = is_active_lvalue(e);
- if (lvalue)
- throw semantic_error("utrace '" + sname + "' variable is read-only", e->tok);
-
- string fname;
- if (sname == "$return")
- {
- if (flags != UDPF_SYSCALL_RETURN)
- throw semantic_error ("only \"process(PATH_OR_PID).syscall.return\" support $return.", e->tok);
- fname = "_utrace_syscall_return";
- }
- else if (sname == "$syscall")
- {
- // If we've got a syscall entry probe, we can just call the
- // right function.
- if (flags == UDPF_SYSCALL) {
- fname = "_utrace_syscall_nr";
- }
- // If we're in a syscal return probe, we can't really access
- // $syscall. So, similar to what
- // dwarf_var_expanding_visitor::visit_target_symbol() does,
- // we'll create an syscall entry probe to cache $syscall, then
- // we'll access the cached value in the syscall return probe.
- else {
- visit_target_symbol_cached (e);
-
- // Remember that we've seen a target variable.
- target_symbol_seen = true;
- return;
- }
- }
- else
- {
- throw semantic_error ("unknown target variable", e->tok);
- }
-
- // Remember that we've seen a target variable.
- target_symbol_seen = true;
-
- // We're going to substitute a synthesized '_utrace_syscall_nr'
- // function call for the '$syscall' reference.
- functioncall* n = new functioncall;
- n->tok = e->tok;
- n->function = fname;
- n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
-
- provide (n);
-}
-
-void
-utrace_var_expanding_visitor::visit_target_symbol (target_symbol* e)
-{
- assert(e->base_name.size() > 0 && e->base_name[0] == '$');
-
- 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);
-
- if (e->base_name.substr(0,4) == "$arg")
- visit_target_symbol_arg(e);
- else if (e->base_name == "$syscall" || e->base_name == "$return")
- visit_target_symbol_context(e);
- else
- throw semantic_error ("invalid target symbol for utrace probe, $syscall, $return or $argN expected",
- e->tok);
-}
-
-
-struct utrace_builder: public derived_probe_builder
-{
- utrace_builder() {}
- virtual void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results)
- {
- string path;
- int64_t pid;
-
- bool has_path = get_param (parameters, TOK_PROCESS, path);
- bool has_pid = get_param (parameters, TOK_PROCESS, pid);
- enum utrace_derived_probe_flags flags = UDPF_NONE;
-
- 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_RETURN;
- else
- flags = UDPF_SYSCALL;
- }
- else if (has_null_param (parameters, TOK_BEGIN))
- flags = UDPF_BEGIN;
- else if (has_null_param (parameters, TOK_END))
- flags = UDPF_END;
-
- // If we didn't get a path or pid, this means to probe everything.
- // Convert this to a pid-based probe.
- if (! has_path && ! has_pid)
- {
- has_path = false;
- path.clear();
- has_pid = true;
- pid = 0;
- }
- else if (has_path)
- {
- path = find_executable (path);
- sess.unwindsym_modules.insert (path);
- }
- else if (has_pid)
- {
- // We can't probe 'init' (pid 1). XXX: where does this limitation come from?
- if (pid < 2)
- throw semantic_error ("process pid must be greater than 1",
- location->tok);
-
- // XXX: could we use /proc/$pid/exe in unwindsym_modules and elsewhere?
- }
-
- finished_results.push_back(new utrace_derived_probe(sess, base, location,
- has_path, path, pid,
- flags));
- }
-};
-
-
-void
-utrace_derived_probe_group::enroll (utrace_derived_probe* p)
-{
- if (p->has_path)
- probes_by_path[p->path].push_back(p);
- else
- probes_by_pid[p->pid].push_back(p);
- num_probes++;
- flags_seen[p->flags] = true;
-
- // XXX: multiple exec probes (for instance) for the same path (or
- // pid) should all share a utrace report function, and have their
- // handlers executed sequentially.
-}
-
-
-void
-utrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
- utrace_derived_probe *p)
-{
- s.op->newline() << "{";
- s.op->line() << " .tgt={";
-
- if (p->has_path)
- {
- s.op->line() << " .pathname=\"" << p->path << "\",";
- s.op->line() << " .pid=0,";
- }
- else
- {
- s.op->line() << " .pathname=NULL,";
- s.op->line() << " .pid=" << p->pid << ",";
- }
-
- s.op->line() << " .callback=&_stp_utrace_probe_cb,";
- s.op->line() << " .mmap_callback=NULL,";
- s.op->line() << " .munmap_callback=NULL,";
- s.op->line() << " .mprotect_callback=NULL,";
- s.op->line() << " },";
- s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ",";
- s.op->line() << " .ph=&" << p->name << ",";
-
- // Handle flags
- switch (p->flags)
- {
- // Notice that we'll just call the probe directly when we get
- // notified, since the task_finder layer stops the thread for us.
- case UDPF_BEGIN: // process begin
- s.op->line() << " .flags=(UDPF_BEGIN),";
- break;
- case UDPF_THREAD_BEGIN: // thread begin
- s.op->line() << " .flags=(UDPF_THREAD_BEGIN),";
- break;
-
- // 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_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. Since the task_finder layer
- // stops the thread, that works around bug 6841.
- 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() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),";
- break;
- 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() << " .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");
- break;
- }
- 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())
- return;
-
- 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 events;";
- s.op->newline() << "int engine_attached;";
- s.op->newline(-1) << "};";
-
-
- // Output handler function for UDPF_BEGIN, UDPF_THREAD_BEGIN,
- // UDPF_END, and UDPF_THREAD_END
- if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN]
- || 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);
-
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp");
-
- // call probe function
- s.op->newline() << "(*p->ph) (c);";
- common_probe_entryfn_epilogue (s.op);
-
- s.op->newline() << "return;";
- s.op->newline(-1) << "}";
- }
-
- // Output handler function for SYSCALL_ENTRY and SYSCALL_EXIT events
- if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
- {
- s.op->newline() << "#ifdef UTRACE_ORIG_VERSION";
- s.op->newline() << "static u32 stap_utrace_probe_syscall(struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
- s.op->newline() << "#else";
- s.op->newline() << "static u32 stap_utrace_probe_syscall(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
- s.op->newline() << "#endif";
-
- s.op->indent(1);
- s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;";
-
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp");
- s.op->newline() << "c->regs = regs;";
-
- // call probe function
- s.op->newline() << "(*p->ph) (c);";
- common_probe_entryfn_epilogue (s.op);
-
- s.op->newline() << "if ((atomic_read (&session_state) != STAP_SESSION_STARTING) && (atomic_read (&session_state) != STAP_SESSION_RUNNING)) {";
- s.op->indent(1);
- s.op->newline() << "debug_task_finder_detach();";
- s.op->newline() << "return UTRACE_DETACH;";
- s.op->newline(-1) << "}";
- s.op->newline() << "return UTRACE_RESUME;";
- s.op->newline(-1) << "}";
- }
-
- // Output task_finder callback routine that gets called for all
- // utrace probe types.
- s.op->newline() << "static int _stp_utrace_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
- 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);";
- s.op->newline() << "struct utrace_attached_engine *engine;";
-
- s.op->newline() << "if (register_p) {";
- s.op->indent(1);
-
- s.op->newline() << "switch (p->flags) {";
- s.op->indent(1);
-
- // 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() << "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_BEGIN])
- {
- s.op->newline() << "case UDPF_THREAD_BEGIN:";
- 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 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() << "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() << "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
- // call stap_utrace_detach_ops() here, only call
- // stap_utrace_detach() as necessary.
- s.op->newline() << "else {";
- s.op->indent(1);
- s.op->newline() << "switch (p->flags) {";
- s.op->indent(1);
- // For end probes, go ahead and call the probe directly.
- 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() << "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, we don't need to do anything.
- if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN])
- {
- s.op->newline() << "case UDPF_BEGIN:";
- s.op->newline() << "case UDPF_THREAD_BEGIN:";
- s.op->indent(1);
- s.op->newline() << "break;";
- s.op->indent(-1);
- }
-
- 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() << "stap_utrace_detach(tsk, &p->ops);";
- 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) << "}";
-
- // Emit vma callbacks.
- s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
- s.op->newline() << "static struct stap_task_finder_target stap_utrace_vmcbs[] = {";
- s.op->indent(1);
- if (! probes_by_path.empty())
- {
- for (p_b_path_iterator it = probes_by_path.begin();
- it != probes_by_path.end(); it++)
- emit_vma_callback_probe_decl (s, it->first, (int64_t)0);
- }
- if (! probes_by_pid.empty())
- {
- for (p_b_pid_iterator it = probes_by_pid.begin();
- it != probes_by_pid.end(); it++)
- emit_vma_callback_probe_decl (s, "", it->first);
- }
- s.op->newline(-1) << "};";
- s.op->newline() << "#endif";
-
- s.op->newline() << "static struct stap_utrace_probe stap_utrace_probes[] = {";
- s.op->indent(1);
-
- // Set up 'process(PATH)' probes
- if (! probes_by_path.empty())
- {
- for (p_b_path_iterator it = probes_by_path.begin();
- it != probes_by_path.end(); it++)
- {
- for (unsigned i = 0; i < it->second.size(); i++)
- {
- utrace_derived_probe *p = it->second[i];
- emit_probe_decl(s, p);
- }
- }
- }
-
- // Set up 'process(PID)' probes
- if (! probes_by_pid.empty())
- {
- for (p_b_pid_iterator it = probes_by_pid.begin();
- it != probes_by_pid.end(); it++)
- {
- for (unsigned i = 0; i < it->second.size(); i++)
- {
- utrace_derived_probe *p = it->second[i];
- emit_probe_decl(s, p);
- }
- }
- }
- s.op->newline(-1) << "};";
-}
-
-
-void
-utrace_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes_by_path.empty() && probes_by_pid.empty())
- return;
-
- s.op->newline();
- s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
- s.op->newline() << "_stp_sym_init();";
- s.op->newline() << "/* ---- utrace vma callbacks ---- */";
- s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_vmcbs); i++) {";
- s.op->indent(1);
- s.op->newline() << "struct stap_task_finder_target *r = &stap_utrace_vmcbs[i];";
- s.op->newline() << "rc = stap_register_task_finder_target(r);";
- s.op->newline(-1) << "}";
- s.op->newline() << "#endif";
-
- s.op->newline() << "/* ---- utrace probes ---- */";
- s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_probes); i++) {";
- s.op->indent(1);
- s.op->newline() << "struct stap_utrace_probe *p = &stap_utrace_probes[i];";
- s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
- s.op->newline(-1) << "}";
-
- // rollback all utrace probes
- s.op->newline() << "if (rc) {";
- s.op->indent(1);
- s.op->newline() << "for (j=i-1; j>=0; j--) {";
- s.op->indent(1);
- s.op->newline() << "struct stap_utrace_probe *p = &stap_utrace_probes[j];";
-
- s.op->newline() << "if (p->engine_attached) {";
- s.op->indent(1);
- s.op->newline() << "stap_utrace_detach_ops(&p->ops);";
- s.op->newline(-1) << "}";
- s.op->newline(-1) << "}";
-
- s.op->newline(-1) << "}";
-}
-
-
-void
-utrace_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes_by_path.empty() && probes_by_pid.empty()) return;
-
- s.op->newline();
- s.op->newline() << "/* ---- utrace probes ---- */";
- s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_probes); i++) {";
- s.op->indent(1);
- s.op->newline() << "struct stap_utrace_probe *p = &stap_utrace_probes[i];";
-
- s.op->newline() << "if (p->engine_attached) {";
- s.op->indent(1);
- s.op->newline() << "stap_utrace_detach_ops(&p->ops);";
- s.op->newline(-1) << "}";
- s.op->newline(-1) << "}";
-}
-
-
// ------------------------------------------------------------------------
// user-space probes
// ------------------------------------------------------------------------
@@ -7963,7 +6289,7 @@ uprobe_derived_probe::join_group (systemtap_session& s)
if (! s.uprobe_derived_probes)
s.uprobe_derived_probes = new uprobe_derived_probe_group ();
s.uprobe_derived_probes->enroll (this);
- task_finder_derived_probe_group::create_session_group (s);
+ enable_task_finder(s);
// Ask buildrun.cxx to build extra module if needed, and
// signal staprun to load that module
@@ -8351,6 +6677,41 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s)
static string TOK_KPROBE("kprobe");
+struct kprobe_derived_probe: public derived_probe
+{
+ kprobe_derived_probe (probe *base,
+ probe_point *location,
+ const string& name,
+ int64_t stmt_addr,
+ bool has_return,
+ bool has_statement,
+ bool has_maxactive,
+ long maxactive_val
+ );
+ string symbol_name;
+ Dwarf_Addr addr;
+ bool has_return;
+ bool has_statement;
+ bool has_maxactive;
+ long maxactive_val;
+ bool access_var;
+ void printsig (std::ostream &o) const;
+ void join_group (systemtap_session& s);
+};
+
+struct kprobe_derived_probe_group: public derived_probe_group
+{
+private:
+ multimap<string,kprobe_derived_probe*> probes_by_module;
+ typedef multimap<string,kprobe_derived_probe*>::iterator p_b_m_iterator;
+
+public:
+ void enroll (kprobe_derived_probe* probe);
+ void emit_module_decls (systemtap_session& s);
+ void emit_module_init (systemtap_session& s);
+ void emit_module_exit (systemtap_session& s);
+};
+
kprobe_derived_probe::kprobe_derived_probe (probe *base,
probe_point *location,
const string& name,
@@ -8757,1479 +7118,6 @@ kprobe_builder::build(systemtap_session & sess,
}
-// ------------------------------------------------------------------------
-// timer derived probes
-// ------------------------------------------------------------------------
-
-
-static string TOK_TIMER("timer");
-
-struct timer_derived_probe: public derived_probe
-{
- int64_t interval, randomize;
- bool time_is_msecs; // NB: hrtimers get ms-based probes on modern kernels instead
- timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r, bool ms=false);
- virtual void join_group (systemtap_session& s);
-};
-
-
-struct timer_derived_probe_group: public generic_dpg<timer_derived_probe>
-{
- void emit_interval (translator_output* o);
-public:
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-
-timer_derived_probe::timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r, bool ms):
- derived_probe (p, l), interval (i), randomize (r), time_is_msecs(ms)
-{
- if (interval <= 0 || interval > 1000000) // make i and r fit into plain ints
- throw semantic_error ("invalid interval for jiffies timer");
- // randomize = 0 means no randomization
- if (randomize < 0 || randomize > interval)
- throw semantic_error ("invalid randomize for jiffies timer");
-
- if (locations.size() != 1)
- throw semantic_error ("expect single probe point");
- // so we don't have to loop over them in the other functions
-}
-
-
-void
-timer_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.timer_derived_probes)
- s.timer_derived_probes = new timer_derived_probe_group ();
- s.timer_derived_probes->enroll (this);
-}
-
-
-void
-timer_derived_probe_group::emit_interval (translator_output* o)
-{
- o->line() << "({";
- o->newline(1) << "unsigned i = stp->intrv;";
- o->newline() << "if (stp->rnd != 0)";
- o->newline(1) << "i += _stp_random_pm(stp->rnd);";
- o->newline(-1) << "stp->ms ? msecs_to_jiffies(i) : i;";
- o->newline(-1) << "})";
-}
-
-
-void
-timer_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "/* ---- timer probes ---- */";
-
- s.op->newline() << "static struct stap_timer_probe {";
- s.op->newline(1) << "struct timer_list timer_list;";
- s.op->newline() << "const char *pp;";
- s.op->newline() << "void (*ph) (struct context*);";
- s.op->newline() << "unsigned intrv, ms, rnd;";
- s.op->newline(-1) << "} stap_timer_probes [" << probes.size() << "] = {";
- s.op->indent(1);
- for (unsigned i=0; i < probes.size(); i++)
- {
- s.op->newline () << "{";
- s.op->line() << " .pp="
- << lex_cast_qstring (*probes[i]->sole_location()) << ",";
- s.op->line() << " .ph=&" << probes[i]->name << ",";
- s.op->line() << " .intrv=" << probes[i]->interval << ",";
- s.op->line() << " .ms=" << probes[i]->time_is_msecs << ",";
- s.op->line() << " .rnd=" << probes[i]->randomize;
- s.op->line() << " },";
- }
- s.op->newline(-1) << "};";
- s.op->newline();
-
- s.op->newline() << "static void enter_timer_probe (unsigned long val) {";
- s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [val];";
- s.op->newline() << "if ((atomic_read (&session_state) == STAP_SESSION_STARTING) ||";
- s.op->newline() << " (atomic_read (&session_state) == STAP_SESSION_RUNNING))";
- s.op->newline(1) << "mod_timer (& stp->timer_list, jiffies + ";
- emit_interval (s.op);
- s.op->line() << ");";
- s.op->newline(-1) << "{";
- s.op->indent(1);
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->pp");
- s.op->newline() << "(*stp->ph) (c);";
- common_probe_entryfn_epilogue (s.op);
- s.op->newline(-1) << "}";
- s.op->newline(-1) << "}";
-}
-
-
-void
-timer_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [i];";
- s.op->newline() << "probe_point = stp->pp;";
- s.op->newline() << "init_timer (& stp->timer_list);";
- s.op->newline() << "stp->timer_list.function = & enter_timer_probe;";
- s.op->newline() << "stp->timer_list.data = i;"; // NB: important!
- // copy timer renew calculations from above :-(
- s.op->newline() << "stp->timer_list.expires = jiffies + ";
- emit_interval (s.op);
- s.op->line() << ";";
- s.op->newline() << "add_timer (& stp->timer_list);";
- // note: no partial failure rollback is needed: add_timer cannot fail.
- s.op->newline(-1) << "}"; // for loop
-}
-
-
-void
-timer_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
- s.op->newline(1) << "del_timer_sync (& stap_timer_probes[i].timer_list);";
- s.op->indent(-1);
-}
-
-
-
-// ------------------------------------------------------------------------
-// profile derived probes
-// ------------------------------------------------------------------------
-// On kernels < 2.6.10, this uses the register_profile_notifier API to
-// generate the timed events for profiling; on kernels >= 2.6.10 this
-// uses the register_timer_hook API. The latter doesn't currently allow
-// simultaneous users, so insertion will fail if the profiler is busy.
-// (Conflicting users may include OProfile, other SystemTap probes, etc.)
-
-
-struct profile_derived_probe: public derived_probe
-{
- profile_derived_probe (systemtap_session &s, probe* p, probe_point* l);
- void join_group (systemtap_session& s);
-};
-
-
-struct profile_derived_probe_group: public generic_dpg<profile_derived_probe>
-{
-public:
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-
-profile_derived_probe::profile_derived_probe (systemtap_session &, probe* p, probe_point* l):
- derived_probe(p, l)
-{
-}
-
-
-void
-profile_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.profile_derived_probes)
- s.profile_derived_probes = new profile_derived_probe_group ();
- s.profile_derived_probes->enroll (this);
-}
-
-
-struct profile_builder: public derived_probe_builder
-{
- profile_builder() {}
- virtual void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const &,
- vector<derived_probe *> & finished_results)
- {
- sess.unwindsym_modules.insert ("kernel");
- finished_results.push_back(new profile_derived_probe(sess, base, location));
- }
-};
-
-
-// timer.profile probe handlers are hooked up in an entertaining way
-// to the underlying kernel facility. The fact that 2.6.11+ era
-// "register_timer_hook" API allows only one consumer *system-wide*
-// will give a hint. We will have a single entry function (and thus
-// trivial registration / unregistration), and it will call all probe
-// handler functions in sequence.
-
-void
-profile_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- // kernels < 2.6.10: use register_profile_notifier API
- // kernels >= 2.6.10: use register_timer_hook API
- s.op->newline() << "/* ---- profile probes ---- */";
-
- // This function calls all the profiling probe handlers in sequence.
- // The only tricky thing is that the context will be reused amongst
- // them. While a simple sequence of calls to the individual probe
- // handlers is unlikely to go terribly wrong (with c->last_error
- // being set causing an early return), but for extra assurance, we
- // open-code the same logic here.
-
- s.op->newline() << "static void enter_all_profile_probes (struct pt_regs *regs) {";
- s.op->indent(1);
- string pp = lex_cast_qstring("timer.profile"); // hard-coded for convenience
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", pp);
- s.op->newline() << "c->regs = regs;";
-
- for (unsigned i=0; i<probes.size(); i++)
- {
- if (i > 0)
- {
- // Some lightweight inter-probe context resetting
- // XXX: not quite right: MAXERRORS not respected
- s.op->newline() << "c->actionremaining = MAXACTION;";
- }
- s.op->newline() << "if (c->last_error == NULL) " << probes[i]->name << " (c);";
- }
- common_probe_entryfn_epilogue (s.op);
- s.op->newline(-1) << "}";
-
- s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
-
- s.op->newline() << "static int enter_profile_probes (struct notifier_block *self,"
- << " unsigned long val, void *data) {";
- s.op->newline(1) << "(void) self; (void) val;";
- s.op->newline() << "enter_all_profile_probes ((struct pt_regs *) data);";
- s.op->newline() << "return 0;";
- s.op->newline(-1) << "}";
- s.op->newline() << "struct notifier_block stap_profile_notifier = {"
- << " .notifier_call = & enter_profile_probes };";
-
- s.op->newline() << "#else";
-
- s.op->newline() << "static int enter_profile_probes (struct pt_regs *regs) {";
- s.op->newline(1) << "enter_all_profile_probes (regs);";
- s.op->newline() << "return 0;";
- s.op->newline(-1) << "}";
-
- s.op->newline() << "#endif";
-}
-
-
-void
-profile_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "probe_point = \"timer.profile\";"; // NB: hard-coded for convenience
- s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
- s.op->newline() << "rc = register_profile_notifier (& stap_profile_notifier);";
- s.op->newline() << "#else";
- s.op->newline() << "rc = register_timer_hook (& enter_profile_probes);";
- s.op->newline() << "#endif";
-}
-
-
-void
-profile_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
- s.op->newline(1) << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
- s.op->newline() << "unregister_profile_notifier (& stap_profile_notifier);";
- s.op->newline() << "#else";
- s.op->newline() << "unregister_timer_hook (& enter_profile_probes);";
- s.op->newline() << "#endif";
- s.op->indent(-1);
-}
-
-
-
-// ------------------------------------------------------------------------
-// procfs file derived probes
-// ------------------------------------------------------------------------
-
-
-static string TOK_PROCFS("procfs");
-static string TOK_READ("read");
-static string TOK_WRITE("write");
-
-struct procfs_derived_probe: public derived_probe
-{
- string path;
- bool write;
- bool target_symbol_seen;
-
- procfs_derived_probe (systemtap_session &, probe* p, probe_point* l, string ps, bool w);
- void join_group (systemtap_session& s);
-};
-
-
-struct procfs_probe_set
-{
- procfs_derived_probe* read_probe;
- procfs_derived_probe* write_probe;
-
- procfs_probe_set () : read_probe (NULL), write_probe (NULL) {}
-};
-
-
-struct procfs_derived_probe_group: public generic_dpg<procfs_derived_probe>
-{
-private:
- map<string, procfs_probe_set*> probes_by_path;
- typedef map<string, procfs_probe_set*>::iterator p_b_p_iterator;
- bool has_read_probes;
- bool has_write_probes;
-
-public:
- procfs_derived_probe_group () :
- has_read_probes(false), has_write_probes(false) {}
-
- void enroll (procfs_derived_probe* probe);
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-
-struct procfs_var_expanding_visitor: public var_expanding_visitor
-{
- procfs_var_expanding_visitor(systemtap_session& s, const string& pn,
- string path, bool write_probe):
- sess (s), probe_name (pn), path (path), write_probe (write_probe),
- target_symbol_seen (false) {}
-
- systemtap_session& sess;
- string probe_name;
- string path;
- bool write_probe;
- bool target_symbol_seen;
-
- void visit_target_symbol (target_symbol* e);
-};
-
-
-procfs_derived_probe::procfs_derived_probe (systemtap_session &s, probe* p,
- probe_point* l, string ps, bool w):
- derived_probe(p, l), path(ps), write(w), target_symbol_seen(false)
-{
- // Expand local variables in the probe body
- procfs_var_expanding_visitor v (s, name, path, write);
- this->body = v.require (this->body);
- target_symbol_seen = v.target_symbol_seen;
-}
-
-
-void
-procfs_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.procfs_derived_probes)
- s.procfs_derived_probes = new procfs_derived_probe_group ();
- s.procfs_derived_probes->enroll (this);
-}
-
-
-void
-procfs_derived_probe_group::enroll (procfs_derived_probe* p)
-{
- procfs_probe_set *pset;
-
- if (probes_by_path.count(p->path) == 0)
- {
- pset = new procfs_probe_set;
- probes_by_path[p->path] = pset;
- }
- else
- {
- pset = probes_by_path[p->path];
-
- // You can only specify 1 read and 1 write probe.
- if (p->write && pset->write_probe != NULL)
- throw semantic_error("only one write procfs probe can exist for procfs path \"" + p->path + "\"");
- else if (! p->write && pset->read_probe != NULL)
- throw semantic_error("only one read procfs probe can exist for procfs path \"" + p->path + "\"");
-
- // XXX: multiple writes should be acceptable
- }
-
- if (p->write)
- {
- pset->write_probe = p;
- has_write_probes = true;
- }
- else
- {
- pset->read_probe = p;
- has_read_probes = true;
- }
-}
-
-
-void
-procfs_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes_by_path.empty())
- return;
-
- s.op->newline() << "/* ---- procfs probes ---- */";
- s.op->newline() << "#include \"procfs.c\"";
-
- // Emit the procfs probe data list
- s.op->newline() << "static struct stap_procfs_probe {";
- s.op->newline(1)<< "const char *path;";
- s.op->newline() << "const char *read_pp;";
- s.op->newline() << "void (*read_ph) (struct context*);";
- s.op->newline() << "const char *write_pp;";
- s.op->newline() << "void (*write_ph) (struct context*);";
- s.op->newline(-1) << "} stap_procfs_probes[] = {";
- s.op->indent(1);
-
- for (p_b_p_iterator it = probes_by_path.begin(); it != probes_by_path.end();
- it++)
- {
- procfs_probe_set *pset = it->second;
-
- s.op->newline() << "{";
- s.op->line() << " .path=" << lex_cast_qstring (it->first) << ",";
-
- if (pset->read_probe != NULL)
- {
- s.op->line() << " .read_pp="
- << lex_cast_qstring (*pset->read_probe->sole_location())
- << ",";
- s.op->line() << " .read_ph=&" << pset->read_probe->name << ",";
- }
- else
- {
- s.op->line() << " .read_pp=NULL,";
- s.op->line() << " .read_ph=NULL,";
- }
-
- if (pset->write_probe != NULL)
- {
- s.op->line() << " .write_pp="
- << lex_cast_qstring (*pset->write_probe->sole_location())
- << ",";
- s.op->line() << " .write_ph=&" << pset->write_probe->name;
- }
- else
- {
- s.op->line() << " .write_pp=NULL,";
- s.op->line() << " .write_ph=NULL";
- }
- s.op->line() << " },";
- }
- s.op->newline(-1) << "};";
-
- if (has_read_probes)
- {
- // Output routine to fill in 'page' with our data.
- s.op->newline();
-
- s.op->newline() << "static int _stp_procfs_read(char *page, char **start, off_t off, int count, int *eof, void *data) {";
-
- s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
- s.op->newline() << "int bytes = 0;";
- s.op->newline() << "string_t strdata = {'\\0'};";
-
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->read_pp");
-
- s.op->newline() << "if (c->data == NULL)";
- s.op->newline(1) << "c->data = &strdata;";
- s.op->newline(-1) << "else {";
-
- s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
- s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
- s.op->newline() << "_stp_exit ();";
- s.op->newline(-1) << "}";
- s.op->newline() << "atomic_dec (& c->busy);";
- s.op->newline() << "goto probe_epilogue;";
- s.op->newline(-1) << "}";
-
- // call probe function (which copies data into strdata)
- s.op->newline() << "(*spp->read_ph) (c);";
-
- // copy string data into 'page'
- s.op->newline() << "c->data = NULL;";
- s.op->newline() << "bytes = strnlen(strdata, MAXSTRINGLEN - 1);";
- s.op->newline() << "if (off >= bytes)";
- s.op->newline(1) << "*eof = 1;";
- s.op->newline(-1) << "else {";
- s.op->newline(1) << "bytes -= off;";
- s.op->newline() << "if (bytes > count)";
- s.op->newline(1) << "bytes = count;";
- s.op->newline(-1) << "memcpy(page, strdata + off, bytes);";
- s.op->newline() << "*start = page;";
- s.op->newline(-1) << "}";
-
- common_probe_entryfn_epilogue (s.op);
- s.op->newline() << "return bytes;";
-
- s.op->newline(-1) << "}";
- }
- if (has_write_probes)
- {
- s.op->newline() << "static int _stp_procfs_write(struct file *file, const char *buffer, unsigned long count, void *data) {";
-
- s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
- s.op->newline() << "string_t strdata = {'\\0'};";
-
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->write_pp");
-
- s.op->newline() << "if (count > (MAXSTRINGLEN - 1))";
- s.op->newline(1) << "count = MAXSTRINGLEN - 1;";
- s.op->newline(-1) << "_stp_copy_from_user(strdata, buffer, count);";
-
- s.op->newline() << "if (c->data == NULL)";
- s.op->newline(1) << "c->data = &strdata;";
- s.op->newline(-1) << "else {";
-
- s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
- s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
- s.op->newline() << "_stp_exit ();";
- s.op->newline(-1) << "}";
- s.op->newline() << "atomic_dec (& c->busy);";
- s.op->newline() << "goto probe_epilogue;";
- s.op->newline(-1) << "}";
-
- // call probe function (which copies data out of strdata)
- s.op->newline() << "(*spp->write_ph) (c);";
-
- s.op->newline() << "c->data = NULL;";
- common_probe_entryfn_epilogue (s.op);
-
- s.op->newline() << "return count;";
- s.op->newline(-1) << "}";
- }
-}
-
-
-void
-procfs_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes_by_path.empty())
- return;
-
- s.op->newline() << "for (i = 0; i < " << probes_by_path.size() << "; i++) {";
- s.op->newline(1) << "struct stap_procfs_probe *spp = &stap_procfs_probes[i];";
-
- s.op->newline() << "if (spp->read_pp)";
- s.op->newline(1) << "probe_point = spp->read_pp;";
- s.op->newline(-1) << "else";
- s.op->newline(1) << "probe_point = spp->write_pp;";
-
- s.op->newline(-1) << "rc = _stp_create_procfs(spp->path, i);";
-
- s.op->newline() << "if (rc) {";
- s.op->newline(1) << "_stp_close_procfs();";
- s.op->newline() << "break;";
- s.op->newline(-1) << "}";
-
- if (has_read_probes)
- {
- s.op->newline() << "if (spp->read_pp)";
- s.op->newline(1) << "_stp_procfs_files[i]->read_proc = &_stp_procfs_read;";
- s.op->newline(-1) << "else";
- s.op->newline(1) << "_stp_procfs_files[i]->read_proc = NULL;";
- s.op->indent(-1);
- }
- else
- s.op->newline() << "_stp_procfs_files[i]->read_proc = NULL;";
-
- if (has_write_probes)
- {
- s.op->newline() << "if (spp->write_pp)";
- s.op->newline(1) << "_stp_procfs_files[i]->write_proc = &_stp_procfs_write;";
- s.op->newline(-1) << "else";
- s.op->newline(1) << "_stp_procfs_files[i]->write_proc = NULL;";
- s.op->indent(-1);
- }
- else
- s.op->newline() << "_stp_procfs_files[i]->write_proc = NULL;";
-
- s.op->newline() << "_stp_procfs_files[i]->data = spp;";
- s.op->newline(-1) << "}"; // for loop
-}
-
-
-void
-procfs_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes_by_path.empty())
- return;
-
- s.op->newline() << "_stp_close_procfs();";
-}
-
-
-void
-procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e)
-{
- assert(e->base_name.size() > 0 && e->base_name[0] == '$');
-
- if (e->base_name != "$value")
- throw semantic_error ("invalid target symbol for procfs probe, $value expected",
- e->tok);
-
- if (e->components.size() > 0)
- {
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("procfs target variable '$value' may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("procfs target variable '$value' may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid use of procfs target variable '$value'",
- e->tok);
- break;
- }
- }
-
- bool lvalue = is_active_lvalue(e);
- if (write_probe && lvalue)
- throw semantic_error("procfs $value variable is read-only in a procfs write probe", e->tok);
- else if (! write_probe && ! lvalue)
- throw semantic_error("procfs $value variable cannot be read in a procfs read probe", e->tok);
-
- // 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(lvalue ? "_procfs_value_set" : "_procfs_value_get")
- + "_" + lex_cast<string>(tick++));
- string locvalue = "CONTEXT->data";
-
- if (! lvalue)
- ec->code = string("strlcpy (THIS->__retvalue, ") + locvalue
- + string(", MAXSTRINGLEN); /* pure */");
- else
- ec->code = string("strlcpy (") + locvalue
- + string(", THIS->value, MAXSTRINGLEN);");
-
- fdecl->name = fname;
- fdecl->body = ec;
- fdecl->type = pe_string;
-
- if (lvalue)
- {
- // Modify the fdecl so it carries a single pe_string formal
- // argument called "value".
-
- vardecl *v = new vardecl;
- v->type = pe_string;
- v->name = "value";
- v->tok = e->tok;
- fdecl->formal_args.push_back(v);
- }
- sess.functions[fdecl->name]=fdecl;
-
- // Synthesize a functioncall.
- functioncall* n = new functioncall;
- n->tok = e->tok;
- n->function = fname;
- n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
-
- if (lvalue)
- {
- // Provide the functioncall to our parent, so that it can be
- // used to substitute for the assignment node immediately above
- // us.
- assert(!target_symbol_setter_functioncalls.empty());
- *(target_symbol_setter_functioncalls.top()) = n;
- }
-
- provide (n);
-}
-
-
-struct procfs_builder: public derived_probe_builder
-{
- procfs_builder() {}
- virtual void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results);
-};
-
-
-void
-procfs_builder::build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results)
-{
- string path;
- 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
- // following 2 probes are attached to different paths:
- //
- // probe procfs("command").read {}"
- // probe procfs.write {}
-
- if (! has_procfs)
- path = "command";
- // If we have a path, we need to validate it.
- else
- {
- string::size_type start_pos, end_pos;
- string component;
- start_pos = 0;
- while ((end_pos = path.find('/', start_pos)) != string::npos)
- {
- // Make sure it doesn't start with '/'.
- if (end_pos == 0)
- throw semantic_error ("procfs path cannot start with a '/'",
- location->tok);
-
- component = path.substr(start_pos, end_pos - start_pos);
- // Make sure it isn't empty.
- if (component.size() == 0)
- throw semantic_error ("procfs path component cannot be empty",
- location->tok);
- // Make sure it isn't relative.
- else if (component == "." || component == "..")
- throw semantic_error ("procfs path cannot be relative (and contain '.' or '..')", location->tok);
-
- start_pos = end_pos + 1;
- }
- component = path.substr(start_pos);
- // Make sure it doesn't end with '/'.
- if (component.size() == 0)
- throw semantic_error ("procfs path cannot end with a '/'", location->tok);
- // Make sure it isn't relative.
- else if (component == "." || component == "..")
- throw semantic_error ("procfs path cannot be relative (and contain '.' or '..')", location->tok);
- }
-
- if (!(has_read ^ has_write))
- throw semantic_error ("need read/write component", location->tok);
-
- finished_results.push_back(new procfs_derived_probe(sess, base, location,
- path, has_write));
-}
-
-
-
-// ------------------------------------------------------------------------
-// statically inserted macro-based derived probes
-// ------------------------------------------------------------------------
-
-static string TOK_FORMAT("format");
-
-struct mark_arg
-{
- bool str;
- string c_type;
- exp_type stp_type;
-};
-
-struct mark_derived_probe: public derived_probe
-{
- mark_derived_probe (systemtap_session &s,
- const string& probe_name, const string& probe_format,
- probe* base_probe, probe_point* location);
-
- systemtap_session& sess;
- string probe_name, probe_format;
- vector <struct mark_arg *> mark_args;
- bool target_symbol_seen;
-
- void join_group (systemtap_session& s);
- void print_dupe_stamp (ostream& o);
- void emit_probe_context_vars (translator_output* o);
- void initialize_probe_context_vars (translator_output* o);
- void printargs (std::ostream &o) const;
-
- void parse_probe_format ();
-};
-
-
-struct mark_derived_probe_group: public generic_dpg<mark_derived_probe>
-{
-public:
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-
-struct mark_var_expanding_visitor: public var_expanding_visitor
-{
- mark_var_expanding_visitor(systemtap_session& s, const string& pn,
- vector <struct mark_arg *> &mark_args):
- sess (s), probe_name (pn), mark_args (mark_args),
- target_symbol_seen (false) {}
- systemtap_session& sess;
- string probe_name;
- vector <struct mark_arg *> &mark_args;
- bool target_symbol_seen;
-
- void visit_target_symbol (target_symbol* e);
- void visit_target_symbol_arg (target_symbol* e);
- void visit_target_symbol_context (target_symbol* e);
-};
-
-
-void
-hex_dump(unsigned char *data, size_t len)
-{
- // Dump data
- size_t idx = 0;
- while (idx < len)
- {
- string char_rep;
-
- clog << " 0x" << setfill('0') << setw(8) << hex << internal << idx;
-
- for (int i = 0; i < 4; i++)
- {
- clog << " ";
- size_t limit = idx + 4;
- while (idx < len && idx < limit)
- {
- clog << setfill('0') << setw(2)
- << ((unsigned) *((unsigned char *)data + idx));
- if (isprint(*((char *)data + idx)))
- char_rep += *((char *)data + idx);
- else
- char_rep += '.';
- idx++;
- }
- while (idx < limit)
- {
- clog << " ";
- idx++;
- }
- }
- clog << " " << char_rep << dec << setfill(' ') << endl;
- }
-}
-
-
-void
-mark_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
-{
- string argnum_s = e->base_name.substr(4,e->base_name.length()-4);
- int argnum = atoi (argnum_s.c_str());
-
- if (argnum < 1 || argnum > (int)mark_args.size())
- throw semantic_error ("invalid marker argument number", e->tok);
-
- if (is_active_lvalue (e))
- throw semantic_error("write to marker parameter not permitted", e->tok);
-
- if (e->components.size() > 0)
- {
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("marker argument may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("marker argument may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid marker argument use", e->tok);
- break;
- }
- }
-
- // Remember that we've seen a target variable.
- target_symbol_seen = true;
-
- e->probe_context_var = "__mark_arg" + lex_cast<string>(argnum);
- e->type = mark_args[argnum-1]->stp_type;
- provide (e);
-}
-
-
-void
-mark_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
-{
- string sname = e->base_name;
-
- if (is_active_lvalue (e))
- throw semantic_error("write to marker '" + sname + "' not permitted", e->tok);
-
- if (e->components.size() > 0)
- {
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("marker '" + sname + "' may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("marker '" + sname + "' may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid marker '" + sname + "' use", e->tok);
- break;
- }
- }
-
- string fname;
- if (e->base_name == "$format") {
- fname = string("_mark_format_get");
- } else {
- fname = string("_mark_name_get");
- }
-
- // Synthesize a functioncall.
- functioncall* n = new functioncall;
- n->tok = e->tok;
- n->function = fname;
- n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
- provide (n);
-}
-
-void
-mark_var_expanding_visitor::visit_target_symbol (target_symbol* e)
-{
- assert(e->base_name.size() > 0 && e->base_name[0] == '$');
-
- if (e->base_name.substr(0,4) == "$arg")
- visit_target_symbol_arg (e);
- else if (e->base_name == "$format" || e->base_name == "$name")
- visit_target_symbol_context (e);
- else
- throw semantic_error ("invalid target symbol for marker, $argN, $name or $format expected",
- e->tok);
-}
-
-
-
-mark_derived_probe::mark_derived_probe (systemtap_session &s,
- const string& p_n,
- const string& p_f,
- probe* base, probe_point* loc):
- derived_probe (base, new probe_point(*loc) /* .components soon rewritten */),
- sess (s), probe_name (p_n), probe_format (p_f),
- target_symbol_seen (false)
-{
- // create synthetic probe point name; preserve condition
- vector<probe_point::component*> comps;
- 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
- parse_probe_format();
-
- // Now expand the local variables in the probe body
- mark_var_expanding_visitor v (sess, name, mark_args);
- this->body = v.require (this->body);
- target_symbol_seen = v.target_symbol_seen;
-
- if (sess.verbose > 2)
- clog << "marker-based " << name << " mark=" << probe_name
- << " fmt='" << probe_format << "'" << endl;
-}
-
-
-static int
-skip_atoi(const char **s)
-{
- int i = 0;
- while (isdigit(**s))
- i = i * 10 + *((*s)++) - '0';
- return i;
-}
-
-
-void
-mark_derived_probe::parse_probe_format()
-{
- const char *fmt = probe_format.c_str();
- int qualifier; // 'h', 'l', or 'L' for integer fields
- mark_arg *arg;
-
- for (; *fmt ; ++fmt)
- {
- if (*fmt != '%')
- {
- /* Skip text */
- continue;
- }
-
-repeat:
- ++fmt;
-
- // skip conversion flags (if present)
- switch (*fmt)
- {
- case '-':
- case '+':
- case ' ':
- case '#':
- case '0':
- goto repeat;
- }
-
- // skip minimum field witdh (if present)
- if (isdigit(*fmt))
- skip_atoi(&fmt);
-
- // skip precision (if present)
- if (*fmt == '.')
- {
- ++fmt;
- if (isdigit(*fmt))
- skip_atoi(&fmt);
- }
-
- // get the conversion qualifier (if present)
- qualifier = -1;
- if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
- {
- qualifier = *fmt;
- ++fmt;
- if (qualifier == 'l' && *fmt == 'l')
- {
- qualifier = 'L';
- ++fmt;
- }
- }
-
- // get the conversion type
- switch (*fmt)
- {
- case 'c':
- arg = new mark_arg;
- arg->str = false;
- arg->c_type = "int";
- arg->stp_type = pe_long;
- mark_args.push_back(arg);
- continue;
-
- case 's':
- arg = new mark_arg;
- arg->str = true;
- arg->c_type = "char *";
- arg->stp_type = pe_string;
- mark_args.push_back(arg);
- continue;
-
- case 'p':
- arg = new mark_arg;
- arg->str = false;
- // This should really be 'void *'. But, then we'll get a
- // compile error when we assign the void pointer to an
- // integer without a cast. So, we use 'long' instead, since
- // it should have the same size as 'void *'.
- arg->c_type = "long";
- arg->stp_type = pe_long;
- mark_args.push_back(arg);
- continue;
-
- case '%':
- continue;
-
- case 'o':
- case 'X':
- case 'x':
- case 'd':
- case 'i':
- case 'u':
- // fall through...
- break;
-
- default:
- if (!*fmt)
- --fmt;
- continue;
- }
-
- arg = new mark_arg;
- arg->str = false;
- arg->stp_type = pe_long;
- switch (qualifier)
- {
- case 'L':
- arg->c_type = "long long";
- break;
-
- case 'l':
- arg->c_type = "long";
- break;
-
- case 'h':
- arg->c_type = "short";
- break;
-
- default:
- arg->c_type = "int";
- break;
- }
- mark_args.push_back(arg);
- }
-}
-
-
-void
-mark_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.mark_derived_probes)
- {
- s.mark_derived_probes = new mark_derived_probe_group ();
-
- // Make sure <linux/marker.h> is included early.
- embeddedcode *ec = new embeddedcode;
- ec->tok = NULL;
- ec->code = string("#if ! defined(CONFIG_MARKERS)\n")
- + string("#error \"Need CONFIG_MARKERS!\"\n")
- + string("#endif\n")
- + string("#include <linux/marker.h>\n");
-
- s.embeds.push_back(ec);
- }
- s.mark_derived_probes->enroll (this);
-}
-
-
-void
-mark_derived_probe::print_dupe_stamp (ostream& o)
-{
- if (target_symbol_seen)
- for (unsigned i = 0; i < mark_args.size(); i++)
- o << mark_args[i]->c_type << " __mark_arg" << (i+1) << endl;
-}
-
-
-void
-mark_derived_probe::emit_probe_context_vars (translator_output* o)
-{
- // If we haven't seen a target symbol for this probe, quit.
- if (! target_symbol_seen)
- return;
-
- for (unsigned i = 0; i < mark_args.size(); i++)
- {
- string localname = "__mark_arg" + lex_cast<string>(i+1);
- switch (mark_args[i]->stp_type)
- {
- case pe_long:
- o->newline() << "int64_t " << localname << ";";
- break;
- case pe_string:
- o->newline() << "string_t " << localname << ";";
- break;
- default:
- throw semantic_error ("cannot expand unknown type");
- break;
- }
- }
-}
-
-
-void
-mark_derived_probe::initialize_probe_context_vars (translator_output* o)
-{
- // If we haven't seen a target symbol for this probe, quit.
- if (! target_symbol_seen)
- return;
-
- bool deref_fault_needed = false;
- for (unsigned i = 0; i < mark_args.size(); i++)
- {
- string localname = "l->__mark_arg" + lex_cast<string>(i+1);
- switch (mark_args[i]->stp_type)
- {
- case pe_long:
- o->newline() << localname << " = va_arg(*c->mark_va_list, "
- << mark_args[i]->c_type << ");";
- break;
-
- case pe_string:
- // We're assuming that this is a kernel string (this code is
- // basically the guts of kernel_string), not a user string.
- o->newline() << "{ " << mark_args[i]->c_type
- << " tmp_str = va_arg(*c->mark_va_list, "
- << mark_args[i]->c_type << ");";
- o->newline() << "deref_string (" << localname
- << ", tmp_str, MAXSTRINGLEN); }";
- deref_fault_needed = true;
- break;
-
- default:
- throw semantic_error ("cannot expand unknown type");
- break;
- }
- }
- if (deref_fault_needed)
- // Need to report errors?
- o->newline() << "deref_fault: ;";
-}
-
-void
-mark_derived_probe::printargs(std::ostream &o) const
-{
- for (unsigned i = 0; i < mark_args.size(); i++)
- {
- string localname = "$arg" + lex_cast<string>(i+1);
- switch (mark_args[i]->stp_type)
- {
- case pe_long:
- o << " " << localname << ":long";
- break;
- case pe_string:
- o << " " << localname << ":string";
- break;
- default:
- o << " " << localname << ":unknown";
- break;
- }
- }
-}
-
-
-void
-mark_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes.empty())
- return;
-
- s.op->newline() << "/* ---- marker probes ---- */";
-
- s.op->newline() << "static struct stap_marker_probe {";
- s.op->newline(1) << "const char * const name;";
- s.op->newline() << "const char * const format;";
- s.op->newline() << "const char * const pp;";
- s.op->newline() << "void (* const ph) (struct context *);";
-
- s.op->newline(-1) << "} stap_marker_probes [" << probes.size() << "] = {";
- s.op->indent(1);
- for (unsigned i=0; i < probes.size(); i++)
- {
- s.op->newline () << "{";
- s.op->line() << " .name=" << lex_cast_qstring(probes[i]->probe_name)
- << ",";
- s.op->line() << " .format=" << lex_cast_qstring(probes[i]->probe_format)
- << ",";
- s.op->line() << " .pp=" << lex_cast_qstring (*probes[i]->sole_location())
- << ",";
- s.op->line() << " .ph=&" << probes[i]->name;
- s.op->line() << " },";
- }
- s.op->newline(-1) << "};";
- s.op->newline();
-
-
- // Emit the marker callback function
- s.op->newline();
- s.op->newline() << "static void enter_marker_probe (void *probe_data, void *call_data, const char *fmt, va_list *args) {";
- s.op->newline(1) << "struct stap_marker_probe *smp = (struct stap_marker_probe *)probe_data;";
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "smp->pp");
- s.op->newline() << "c->marker_name = smp->name;";
- s.op->newline() << "c->marker_format = smp->format;";
- s.op->newline() << "c->mark_va_list = args;";
- s.op->newline() << "(*smp->ph) (c);";
- s.op->newline() << "c->mark_va_list = NULL;";
- s.op->newline() << "c->data = NULL;";
-
- common_probe_entryfn_epilogue (s.op);
- s.op->newline(-1) << "}";
-
- return;
-}
-
-
-void
-mark_derived_probe_group::emit_module_init (systemtap_session &s)
-{
- if (probes.size () == 0)
- return;
-
- s.op->newline() << "/* init marker probes */";
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];";
- s.op->newline() << "probe_point = smp->pp;";
- s.op->newline() << "rc = marker_probe_register(smp->name, smp->format, enter_marker_probe, smp);";
- s.op->newline() << "if (rc) {";
- s.op->newline(1) << "for (j=i-1; j>=0; j--) {"; // partial rollback
- s.op->newline(1) << "struct stap_marker_probe *smp2 = &stap_marker_probes[j];";
- s.op->newline() << "marker_probe_unregister(smp2->name, enter_marker_probe, smp2);";
- s.op->newline(-1) << "}";
- s.op->newline() << "break;"; // don't attempt to register any more probes
- s.op->newline(-1) << "}";
- s.op->newline(-1) << "}"; // for loop
-}
-
-
-void
-mark_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes.empty())
- return;
-
- s.op->newline() << "/* deregister marker probes */";
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];";
- s.op->newline() << "marker_probe_unregister(smp->name, enter_marker_probe, smp);";
- s.op->newline(-1) << "}"; // for loop
-}
-
-
-struct mark_builder: public derived_probe_builder
-{
-private:
- bool cache_initialized;
- typedef multimap<string, string> mark_cache_t;
- typedef multimap<string, string>::const_iterator mark_cache_const_iterator_t;
- typedef pair<mark_cache_const_iterator_t, mark_cache_const_iterator_t>
- mark_cache_const_iterator_pair_t;
- mark_cache_t mark_cache;
-
-public:
- mark_builder(): cache_initialized(false) {}
-
- void build_no_more (systemtap_session &s)
- {
- if (! mark_cache.empty())
- {
- if (s.verbose > 3)
- clog << "mark_builder releasing cache" << endl;
- mark_cache.clear();
- }
- }
-
- void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results);
-};
-
-
-void
-mark_builder::build(systemtap_session & sess,
- probe * base,
- probe_point *loc,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results)
-{
- string 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, TOK_FORMAT, mark_format_val);
- assert (has_mark_str);
- (void) has_mark_str;
-
- if (! cache_initialized)
- {
- cache_initialized = true;
- string module_markers_path = sess.kernel_build_tree + "/Module.markers";
-
- ifstream module_markers;
- module_markers.open(module_markers_path.c_str(), ifstream::in);
- if (! module_markers)
- {
- if (sess.verbose>3)
- clog << module_markers_path << " cannot be opened: "
- << strerror(errno) << endl;
- return;
- }
-
- string name, module, format;
- do
- {
- module_markers >> name >> module;
- getline(module_markers, format);
-
- // trim leading whitespace
- string::size_type notwhite = format.find_first_not_of(" \t");
- format.erase(0, notwhite);
-
- // If the format is empty, make sure we add back a space
- // character, which is what MARK_NOARGS expands to.
- if (format.length() == 0)
- format = " ";
-
- if (sess.verbose>3)
- clog << "'" << name << "' '" << module << "' '" << format
- << "'" << endl;
-
- if (mark_cache.count(name) > 0)
- {
- // If we have 2 markers with the same we've got 2 cases:
- // different format strings or duplicate format strings.
- // If an existing marker in the cache doesn't have the
- // same format string, add this marker.
- mark_cache_const_iterator_pair_t ret;
- mark_cache_const_iterator_t it;
- bool matching_format_string = false;
-
- ret = mark_cache.equal_range(name);
- for (it = ret.first; it != ret.second; ++it)
- {
- if (format == it->second)
- {
- matching_format_string = true;
- break;
- }
- }
-
- if (! matching_format_string)
- mark_cache.insert(pair<string,string>(name, format));
- }
- else
- mark_cache.insert(pair<string,string>(name, format));
- }
- while (! module_markers.eof());
- module_markers.close();
- }
-
- // Search marker list for matching markers
- for (mark_cache_const_iterator_t it = mark_cache.begin();
- it != mark_cache.end(); it++)
- {
- // Below, "rc" has negative polarity: zero iff matching.
- int rc = fnmatch(mark_str_val.c_str(), it->first.c_str(), 0);
- if (! rc)
- {
- bool add_result = true;
-
- // Match format strings (if the user specified one)
- if (has_mark_format && fnmatch(mark_format_val.c_str(),
- it->second.c_str(), 0))
- add_result = false;
-
- if (add_result)
- {
- derived_probe *dp
- = new mark_derived_probe (sess,
- it->first, it->second,
- base, loc);
- finished_results.push_back (dp);
- }
- }
- }
-}
-
-
// ------------------------------------------------------------------------
// statically inserted kernel-tracepoint derived probes
@@ -11054,757 +7942,19 @@ tracepoint_builder::build(systemtap_session& s,
// ------------------------------------------------------------------------
-// hrtimer derived probes
-// ------------------------------------------------------------------------
-// This is a new timer interface that provides more flexibility in specifying
-// intervals, and uses the hrtimer APIs when available for greater precision.
-// While hrtimers were added in 2.6.16, the API's weren't exported until
-// 2.6.17, so we must check this kernel version before attempting to use
-// hrtimers.
-//
-// * hrtimer_derived_probe: creates a probe point based on the hrtimer APIs.
-
-
-struct hrtimer_derived_probe: public derived_probe
-{
- // set a (generous) maximum of one day in ns
- static const int64_t max_ns_interval = 1000000000LL * 60LL * 60LL * 24LL;
-
- // 100us seems like a reasonable minimum
- static const int64_t min_ns_interval = 100000LL;
-
- int64_t interval, randomize;
-
- hrtimer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r,
- int64_t scale):
- derived_probe (p, l), interval (i), randomize (r)
- {
- if ((i < min_ns_interval) || (i > max_ns_interval))
- throw semantic_error(string("interval value out of range (")
- + lex_cast<string>(scale < min_ns_interval
- ? min_ns_interval/scale : 1)
- + ","
- + lex_cast<string>(max_ns_interval/scale) + ")");
-
- // randomize = 0 means no randomization
- if ((r < 0) || (r > i))
- throw semantic_error("randomization value out of range");
- }
-
- void join_group (systemtap_session& s);
-};
-
-
-struct hrtimer_derived_probe_group: public generic_dpg<hrtimer_derived_probe>
-{
- void emit_interval (translator_output* o);
-public:
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-
-void
-hrtimer_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.hrtimer_derived_probes)
- s.hrtimer_derived_probes = new hrtimer_derived_probe_group ();
- s.hrtimer_derived_probes->enroll (this);
-}
-
-
-void
-hrtimer_derived_probe_group::emit_interval (translator_output* o)
-{
- o->line() << "({";
- o->newline(1) << "unsigned long nsecs;";
- o->newline() << "int64_t i = stp->intrv;";
- o->newline() << "if (stp->rnd != 0) {";
- // XXX: why not use stp_random_pm instead of this?
- o->newline(1) << "int64_t r;";
- o->newline() << "get_random_bytes(&r, sizeof(r));";
- // ensure that r is positive
- o->newline() << "r &= ((uint64_t)1 << (8*sizeof(r) - 1)) - 1;";
- o->newline() << "r = _stp_mod64(NULL, r, (2*stp->rnd+1));";
- o->newline() << "r -= stp->rnd;";
- o->newline() << "i += r;";
- o->newline(-1) << "}";
- o->newline() << "if (unlikely(i < stap_hrtimer_resolution))";
- o->newline(1) << "i = stap_hrtimer_resolution;";
- o->indent(-1);
- o->newline() << "nsecs = do_div(i, NSEC_PER_SEC);";
- o->newline() << "ktime_set(i, nsecs);";
- o->newline(-1) << "})";
-}
-
-
-void
-hrtimer_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "/* ---- hrtimer probes ---- */";
-
- s.op->newline() << "static unsigned long stap_hrtimer_resolution;"; // init later
- s.op->newline() << "static struct stap_hrtimer_probe {";
- s.op->newline(1) << "struct hrtimer hrtimer;";
- s.op->newline() << "const char *pp;";
- s.op->newline() << "void (*ph) (struct context*);";
- s.op->newline() << "int64_t intrv, rnd;";
- s.op->newline(-1) << "} stap_hrtimer_probes [" << probes.size() << "] = {";
- s.op->indent(1);
- for (unsigned i=0; i < probes.size(); i++)
- {
- s.op->newline () << "{";
- s.op->line() << " .pp=" << lex_cast_qstring (*probes[i]->sole_location()) << ",";
- s.op->line() << " .ph=&" << probes[i]->name << ",";
- s.op->line() << " .intrv=" << probes[i]->interval << "LL,";
- s.op->line() << " .rnd=" << probes[i]->randomize << "LL";
- s.op->line() << " },";
- }
- s.op->newline(-1) << "};";
- s.op->newline();
-
- // autoconf: add get/set expires if missing (pre 2.6.28-rc1)
- s.op->newline() << "#ifndef STAPCONF_HRTIMER_GETSET_EXPIRES";
- s.op->newline() << "#define hrtimer_get_expires(timer) ((timer)->expires)";
- s.op->newline() << "#define hrtimer_set_expires(timer, time) (void)((timer)->expires = (time))";
- s.op->newline() << "#endif";
-
- // autoconf: adapt to HRTIMER_REL -> HRTIMER_MODE_REL renaming near 2.6.21
- s.op->newline() << "#ifdef STAPCONF_HRTIMER_REL";
- s.op->newline() << "#define HRTIMER_MODE_REL HRTIMER_REL";
- s.op->newline() << "#endif";
-
- // The function signature changed in 2.6.21.
- s.op->newline() << "#ifdef STAPCONF_HRTIMER_REL";
- s.op->newline() << "static int ";
- s.op->newline() << "#else";
- s.op->newline() << "static enum hrtimer_restart ";
- s.op->newline() << "#endif";
- s.op->newline() << "enter_hrtimer_probe (struct hrtimer *timer) {";
-
- s.op->newline(1) << "int rc = HRTIMER_NORESTART;";
- s.op->newline() << "struct stap_hrtimer_probe *stp = container_of(timer, struct stap_hrtimer_probe, hrtimer);";
- s.op->newline() << "if ((atomic_read (&session_state) == STAP_SESSION_STARTING) ||";
- s.op->newline() << " (atomic_read (&session_state) == STAP_SESSION_RUNNING)) {";
- // Compute next trigger time
- s.op->newline(1) << "hrtimer_set_expires(timer, ktime_add (hrtimer_get_expires(timer),";
- emit_interval (s.op);
- s.op->line() << "));";
- s.op->newline() << "rc = HRTIMER_RESTART;";
- s.op->newline(-1) << "}";
- s.op->newline() << "{";
- s.op->indent(1);
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->pp");
- s.op->newline() << "(*stp->ph) (c);";
- common_probe_entryfn_epilogue (s.op);
- s.op->newline(-1) << "}";
- s.op->newline() << "return rc;";
- s.op->newline(-1) << "}";
-}
-
-
-void
-hrtimer_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "{";
- s.op->newline(1) << "struct timespec res;";
- s.op->newline() << "hrtimer_get_res (CLOCK_MONOTONIC, &res);";
- s.op->newline() << "stap_hrtimer_resolution = timespec_to_ns (&res);";
- s.op->newline(-1) << "}";
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_hrtimer_probe* stp = & stap_hrtimer_probes [i];";
- s.op->newline() << "probe_point = stp->pp;";
- s.op->newline() << "hrtimer_init (& stp->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);";
- s.op->newline() << "stp->hrtimer.function = & enter_hrtimer_probe;";
- // There is no hrtimer field to identify *this* (i-th) probe handler
- // callback. So instead we'll deduce it at entry time.
- s.op->newline() << "(void) hrtimer_start (& stp->hrtimer, ";
- emit_interval (s.op);
- s.op->line() << ", HRTIMER_MODE_REL);";
- // Note: no partial failure rollback is needed: hrtimer_start only
- // "fails" if the timer was already active, which cannot be.
- s.op->newline(-1) << "}"; // for loop
-}
-
-
-void
-hrtimer_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
- s.op->newline(1) << "hrtimer_cancel (& stap_hrtimer_probes[i].hrtimer);";
- s.op->indent(-1);
-}
-
-
-
-struct timer_builder: public derived_probe_builder
-{
- virtual void build(systemtap_session & sess,
- probe * base, probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results);
-
- static void register_patterns(systemtap_session& s);
-};
-
-void
-timer_builder::build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results)
-{
- int64_t scale=1, period, rand=0;
-
- if (!get_param(parameters, "randomize", rand))
- rand = 0;
-
- if (get_param(parameters, "jiffies", period))
- {
- // always use basic timers for jiffies
- finished_results.push_back(
- new timer_derived_probe(base, location, period, rand, false));
- return;
- }
- else if (get_param(parameters, "hz", period))
- {
- if (period <= 0)
- throw semantic_error ("frequency must be greater than 0");
- period = (1000000000 + period - 1)/period;
- }
- else if (get_param(parameters, "s", period)
- || get_param(parameters, "sec", period))
- {
- scale = 1000000000;
- period *= scale;
- rand *= scale;
- }
- else if (get_param(parameters, "ms", period)
- || get_param(parameters, "msec", period))
- {
- scale = 1000000;
- period *= scale;
- rand *= scale;
- }
- else if (get_param(parameters, "us", period)
- || get_param(parameters, "usec", period))
- {
- scale = 1000;
- period *= scale;
- rand *= scale;
- }
- else if (get_param(parameters, "ns", period)
- || get_param(parameters, "nsec", period))
- {
- // ok
- }
- else
- throw semantic_error ("unrecognized timer variant");
-
- // Redirect wallclock-time based probes to hrtimer code on recent
- // enough kernels.
- if (strverscmp(sess.kernel_base_release.c_str(), "2.6.17") < 0)
- {
- // hrtimers didn't exist, so use the old-school timers
- period = (period + 1000000 - 1)/1000000;
- rand = (rand + 1000000 - 1)/1000000;
-
- finished_results.push_back(
- new timer_derived_probe(base, location, period, rand, true));
- }
- else
- finished_results.push_back(
- new hrtimer_derived_probe(base, location, period, rand, scale));
-}
-
-void
-timer_builder::register_patterns(systemtap_session& s)
-{
- match_node* root = s.pattern_root;
- derived_probe_builder *builder = new timer_builder();
-
- root = root->bind(TOK_TIMER);
-
- root->bind_num("s")->bind(builder);
- root->bind_num("s")->bind_num("randomize")->bind(builder);
- root->bind_num("sec")->bind(builder);
- root->bind_num("sec")->bind_num("randomize")->bind(builder);
-
- root->bind_num("ms")->bind(builder);
- root->bind_num("ms")->bind_num("randomize")->bind(builder);
- root->bind_num("msec")->bind(builder);
- root->bind_num("msec")->bind_num("randomize")->bind(builder);
-
- root->bind_num("us")->bind(builder);
- root->bind_num("us")->bind_num("randomize")->bind(builder);
- root->bind_num("usec")->bind(builder);
- root->bind_num("usec")->bind_num("randomize")->bind(builder);
-
- root->bind_num("ns")->bind(builder);
- root->bind_num("ns")->bind_num("randomize")->bind(builder);
- root->bind_num("nsec")->bind(builder);
- root->bind_num("nsec")->bind_num("randomize")->bind(builder);
-
- root->bind_num("jiffies")->bind(builder);
- root->bind_num("jiffies")->bind_num("randomize")->bind(builder);
-
- root->bind_num("hz")->bind(builder);
-}
-
-
-
-// ------------------------------------------------------------------------
-// perfmon derived probes
-// ------------------------------------------------------------------------
-// This is a new interface to the perfmon hw.
-//
-
-
-struct perfmon_var_expanding_visitor: public var_expanding_visitor
-{
- systemtap_session & sess;
- unsigned counter_number;
- perfmon_var_expanding_visitor(systemtap_session & s, unsigned c):
- sess(s), counter_number(c) {}
- void visit_target_symbol (target_symbol* e);
-};
-
-
-void
-perfmon_var_expanding_visitor::visit_target_symbol (target_symbol *e)
-{
- assert(e->base_name.size() > 0 && e->base_name[0] == '$');
-
- // Synthesize a function.
- functiondecl *fdecl = new functiondecl;
- fdecl->tok = e->tok;
- embeddedcode *ec = new embeddedcode;
- ec->tok = e->tok;
- bool lvalue = is_active_lvalue(e);
-
- if (lvalue )
- throw semantic_error("writes to $counter not permitted");
-
- string fname = string("_perfmon_tvar_get")
- + "_" + e->base_name.substr(1)
- + "_" + lex_cast<string>(counter_number);
-
- if (e->base_name != "$counter")
- throw semantic_error ("target variables not available to perfmon probes");
-
- if (e->components.size() > 0)
- {
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("perfmon probe '$counter' variable may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("perfmon probe '$counter' variable may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid use of perfmon probe '$counter' variable",
- e->tok);
- break;
- }
- }
-
- ec->code = "THIS->__retvalue = _pfm_pmd_x[" +
- lex_cast<string>(counter_number) + "].reg_num;";
- ec->code += "/* pure */";
- fdecl->name = fname;
- fdecl->body = ec;
- fdecl->type = pe_long;
- sess.functions[fdecl->name]=fdecl;
-
- // Synthesize a functioncall.
- functioncall* n = new functioncall;
- n->tok = e->tok;
- n->function = fname;
- n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
-
- provide (n);
-}
-
-
-enum perfmon_mode
-{
- perfmon_count,
- perfmon_sample
-};
-
-
-struct perfmon_derived_probe: public derived_probe
-{
-protected:
- static unsigned probes_allocated;
-
-public:
- systemtap_session & sess;
- string event;
- perfmon_mode mode;
-
- perfmon_derived_probe (probe* p, probe_point* l, systemtap_session &s,
- string e, perfmon_mode m);
- virtual void join_group (systemtap_session& s);
-};
-
-
-struct perfmon_derived_probe_group: public generic_dpg<perfmon_derived_probe>
-{
-public:
- void emit_module_decls (systemtap_session&) {}
- void emit_module_init (systemtap_session&) {}
- void emit_module_exit (systemtap_session&) {}
-};
-
-
-struct perfmon_builder: public derived_probe_builder
-{
- perfmon_builder() {}
- virtual void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results)
- {
- string event;
- if (!get_param (parameters, "counter", event))
- throw semantic_error("perfmon requires an event");
-
- sess.perfmon++;
-
- // XXX: need to revise when doing sampling
- finished_results.push_back(new perfmon_derived_probe(base, location,
- sess, event,
- perfmon_count));
- }
-};
-
-
-unsigned perfmon_derived_probe::probes_allocated;
-
-perfmon_derived_probe::perfmon_derived_probe (probe* p, probe_point* l,
- systemtap_session &s,
- string e, perfmon_mode m)
- : derived_probe (p, l), sess(s), event(e), mode(m)
-{
- ++probes_allocated;
-
- // Now expand the local variables in the probe body
- perfmon_var_expanding_visitor v (sess, probes_allocated-1);
- this->body = v.require (this->body);
-
- if (sess.verbose > 1)
- clog << "perfmon-based probe" << endl;
-}
-
-
-void
-perfmon_derived_probe::join_group (systemtap_session& s)
-{
- throw semantic_error ("incomplete", this->tok);
-
- if (! s.perfmon_derived_probes)
- s.perfmon_derived_probes = new perfmon_derived_probe_group ();
- s.perfmon_derived_probes->enroll (this);
-}
-
-
-#if 0
-void
-perfmon_derived_probe::emit_registrations_start (translator_output* o,
- unsigned index)
-{
- for (unsigned i=0; i<locations.size(); i++)
- o->newline() << "enter_" << name << "_" << i << " ();";
-}
-
-
-void
-perfmon_derived_probe::emit_registrations_end (translator_output * o,
- unsigned index)
-{
-}
-
-
-void
-perfmon_derived_probe::emit_deregistrations (translator_output * o)
-{
-}
-
-
-void
-perfmon_derived_probe::emit_probe_entries (translator_output * o)
-{
- o->newline() << "#ifdef STP_TIMING";
- // NB: This variable may be multiply (but identically) defined.
- o->newline() << "static __cacheline_aligned Stat " << "time_" << basest()->name << ";";
- o->newline() << "#endif";
-
- for (unsigned i=0; i<locations.size(); i++)
- {
- probe_point *l = locations[i];
- o->newline() << "/* location " << i << ": " << *l << " */";
- o->newline() << "static void enter_" << name << "_" << i << " (void) {";
-
- o->indent(1);
- o->newline() << "const char* probe_point = "
- << lex_cast_qstring(*l) << ";";
- emit_probe_prologue (o,
- (mode == perfmon_count ?
- "STAP_SESSION_STARTING" :
- "STAP_SESSION_RUNNING"),
- "probe_point");
-
- // NB: locals are initialized by probe function itself
- o->newline() << name << " (c);";
-
- emit_probe_epilogue (o);
-
- o->newline(-1) << "}\n";
- }
-}
-#endif
-
-
-#if 0
-void no_pfm_event_error (string s)
-{
- string msg(string("Cannot find event:" + s));
- throw semantic_error(msg);
-}
-
-
-void no_pfm_mask_error (string s)
-{
- string msg(string("Cannot find mask:" + s));
- throw semantic_error(msg);
-}
-
-
-void
-split(const string& s, vector<string>& v, const string & separator)
-{
- string::size_type last_pos = s.find_first_not_of(separator, 0);
- string::size_type pos = s.find_first_of(separator, last_pos);
-
- while (string::npos != pos || string::npos != last_pos) {
- v.push_back(s.substr(last_pos, pos - last_pos));
- last_pos = s.find_first_not_of(separator, pos);
- pos = s.find_first_of(separator, last_pos);
- }
-}
-
-
-void
-perfmon_derived_probe_group::emit_probes (translator_output* op, unparser* up)
-{
- for (unsigned i=0; i < probes.size(); i++)
- {
- op->newline ();
- up->emit_probe (probes[i]);
- }
-}
-
-
-void
-perfmon_derived_probe_group::emit_module_init (translator_output* o)
-{
- int ret;
- pfmlib_input_param_t inp;
- pfmlib_output_param_t outp;
- pfarg_pmd_t pd[PFMLIB_MAX_PMDS];
- pfarg_pmc_t pc[PFMLIB_MAX_PMCS];
- pfarg_ctx_t ctx;
- pfarg_load_t load_args;
- pfmlib_options_t pfmlib_options;
- unsigned int max_counters;
-
- if ( probes.size() == 0)
- return;
- ret = pfm_initialize();
- if (ret != PFMLIB_SUCCESS)
- throw semantic_error("Unable to generate performance monitoring events (no libpfm)");
-
- pfm_get_num_counters(&max_counters);
-
- memset(&pfmlib_options, 0, sizeof(pfmlib_options));
- pfmlib_options.pfm_debug = 0; /* set to 1 for debug */
- pfmlib_options.pfm_verbose = 0; /* set to 1 for debug */
- pfm_set_options(&pfmlib_options);
-
- memset(pd, 0, sizeof(pd));
- memset(pc, 0, sizeof(pc));
- memset(&ctx, 0, sizeof(ctx));
- memset(&load_args, 0, sizeof(load_args));
-
- /*
- * prepare parameters to library.
- */
- memset(&inp,0, sizeof(inp));
- memset(&outp,0, sizeof(outp));
-
- /* figure out the events */
- for (unsigned i=0; i<probes.size(); ++i)
- {
- if (probes[i]->event == "cycles") {
- if (pfm_get_cycle_event( &inp.pfp_events[i].event) != PFMLIB_SUCCESS)
- no_pfm_event_error(probes[i]->event);
- } else if (probes[i]->event == "instructions") {
- if (pfm_get_inst_retired_event( &inp.pfp_events[i].event) !=
- PFMLIB_SUCCESS)
- no_pfm_event_error(probes[i]->event);
- } else {
- unsigned int event_id = 0;
- unsigned int mask_id = 0;
- vector<string> event_spec;
- split(probes[i]->event, event_spec, ":");
- int num = event_spec.size();
- int masks = num - 1;
-
- if (num == 0)
- throw semantic_error("No events found");
-
- /* setup event */
- if (pfm_find_event(event_spec[0].c_str(), &event_id) != PFMLIB_SUCCESS)
- no_pfm_event_error(event_spec[0]);
- inp.pfp_events[i].event = event_id;
-
- /* set up masks */
- if (masks > PFMLIB_MAX_MASKS_PER_EVENT)
- throw semantic_error("Too many unit masks specified");
-
- for (int j=0; j < masks; j++) {
- if (pfm_find_event_mask(event_id, event_spec[j+1].c_str(),
- &mask_id) != PFMLIB_SUCCESS)
- no_pfm_mask_error(string(event_spec[j+1]));
- inp.pfp_events[i].unit_masks[j] = mask_id;
- }
- inp.pfp_events[i].num_masks = masks;
- }
- }
-
- /* number of counters in use */
- inp.pfp_event_count = probes.size();
-
- // XXX: no elimination of duplicated counters
- if (inp.pfp_event_count>max_counters)
- throw semantic_error("Too many performance monitoring events.");
-
- /* count events both in kernel and user-space */
- inp.pfp_dfl_plm = PFM_PLM0 | PFM_PLM3;
-
- /* XXX: some cases a perfmon register might be used of watch dog
- this code doesn't handle that case */
-
- /* figure out the pmcs for the events */
- if ((ret=pfm_dispatch_events(&inp, NULL, &outp, NULL)) != PFMLIB_SUCCESS)
- throw semantic_error("Cannot configure events");
-
- for (unsigned i=0; i < outp.pfp_pmc_count; i++) {
- pc[i].reg_num = outp.pfp_pmcs[i].reg_num;
- pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
- }
-
- /*
- * There could be more pmc settings than pmd.
- * Figure out the actual pmds to use.
- */
- for (unsigned i=0, j=0; i < inp.pfp_event_count; i++) {
- pd[i].reg_num = outp.pfp_pmcs[j].reg_pmd_num;
- for(; j < outp.pfp_pmc_count; j++)
- if (outp.pfp_pmcs[j].reg_evt_idx != i) break;
- }
-
- // Output the be probes create function
- o->newline() << "static int register_perfmon_probes (void) {";
- o->newline(1) << "int rc = 0;";
-
- o->newline() << "/* data for perfmon */";
- o->newline() << "static int _pfm_num_pmc = " << outp.pfp_pmc_count << ";";
- o->newline() << "static struct pfarg_pmc _pfm_pmc[" << outp.pfp_pmc_count
- << "] = {";
- /* output the needed bits for pmc here */
- for (unsigned i=0; i < outp.pfp_pmc_count; i++) {
- o->newline() << "{.reg_num=" << pc[i].reg_num << ", "
- << ".reg_value=" << lex_cast_hex<string>(pc[i].reg_value)
- << "},";
- }
-
- o->newline() << "};";
- o->newline() << "static int _pfm_num_pmd = " << inp.pfp_event_count << ";";
- o->newline() << "static struct pfarg_pmd _pfm_pmd[" << inp.pfp_event_count
- << "] = {";
- /* output the needed bits for pmd here */
- for (unsigned i=0; i < inp.pfp_event_count; i++) {
- o->newline() << "{.reg_num=" << pd[i].reg_num << ", "
- << ".reg_value=" << pd[i].reg_value << "},";
- }
- o->newline() << "};";
- o->newline();
-
- o->newline() << "_pfm_pmc_x=_pfm_pmc;";
- o->newline() << "_pfm_num_pmc_x=_pfm_num_pmc;";
- o->newline() << "_pfm_pmd_x=_pfm_pmd;";
- o->newline() << "_pfm_num_pmd_x=_pfm_num_pmd;";
-
- // call all the function bodies associated with perfcounters
- for (unsigned i=0; i < probes.size (); i++)
- probes[i]->emit_registrations_start (o,i);
-
- /* generate call to turn on instrumentation */
- o->newline() << "_pfm_context.ctx_flags |= PFM_FL_SYSTEM_WIDE;";
- o->newline() << "rc = rc || _stp_perfmon_setup(&_pfm_desc, &_pfm_context,";
- o->newline(1) << "_pfm_pmc, _pfm_num_pmc,";
- o->newline() << "_pfm_pmd, _pfm_num_pmd);";
- o->newline(-1);
-
- o->newline() << "return rc;";
- o->newline(-1) << "}\n";
-
- // Output the be probes destroy function
- o->newline() << "static void unregister_perfmon_probes (void) {";
- o->newline(1) << "_stp_perfmon_shutdown(_pfm_desc);";
- o->newline(-1) << "}\n";
-}
-#endif
-
-// ------------------------------------------------------------------------
-// kprobes-based probes,which postpone symbol resolution until runtime.
-// ------------------------------------------------------------------------
-
-
-// ------------------------------------------------------------------------
// Standard tapset registry.
// ------------------------------------------------------------------------
void
register_standard_tapsets(systemtap_session & s)
{
- s.pattern_root->bind(TOK_BEGIN)->allow_unprivileged()->bind(new be_builder(BEGIN));
- s.pattern_root->bind_num(TOK_BEGIN)->allow_unprivileged()->bind(new be_builder(BEGIN));
- s.pattern_root->bind(TOK_END)->allow_unprivileged()->bind(new be_builder(END));
- s.pattern_root->bind_num(TOK_END)->allow_unprivileged()->bind(new be_builder(END));
- s.pattern_root->bind(TOK_ERROR)->allow_unprivileged()->bind(new be_builder(ERROR));
- s.pattern_root->bind_num(TOK_ERROR)->allow_unprivileged()->bind(new be_builder(ERROR));
-
- s.pattern_root->bind(TOK_NEVER)->allow_unprivileged()->bind(new never_builder());
-
- timer_builder::register_patterns(s);
- s.pattern_root->bind(TOK_TIMER)->bind("profile")->bind(new profile_builder());
- s.pattern_root->bind("perfmon")->bind_str("counter")
- ->bind(new perfmon_builder());
+ register_tapset_been(s);
+ register_tapset_itrace(s);
+ register_tapset_mark(s);
+ register_tapset_perfmon(s);
+ register_tapset_procfs(s);
+ register_tapset_timers(s);
+ register_tapset_utrace(s);
// dwarf-based kprobe/uprobe parts
dwarf_derived_probe::register_patterns(s);
@@ -11817,72 +7967,10 @@ register_standard_tapsets(systemtap_session & s)
->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)->bind(TOK_RETURN)
->bind(new uprobe_builder ());
- // utrace user-space probes
- s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_BEGIN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_BEGIN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind(TOK_PROCESS)->bind(TOK_BEGIN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_END)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_END)
- ->bind(new utrace_builder ());
- s.pattern_root->bind(TOK_PROCESS)->bind(TOK_END)
- ->bind(new utrace_builder ());
- 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(TOK_THREAD)->bind(TOK_BEGIN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN)
- ->bind(new utrace_builder ());
- 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(TOK_THREAD)->bind(TOK_END)
- ->bind(new utrace_builder ());
- s.pattern_root->bind(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL)
- ->bind(new utrace_builder ());
- s.pattern_root->bind(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 ());
- s.pattern_root->bind(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN)
- ->bind(new utrace_builder ());
-
- // itrace user-space probes
- s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_INSN)
- ->bind(new itrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_INSN)
- ->bind(new itrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)
- ->bind(new itrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)
- ->bind(new itrace_builder ());
-
- // marker-based parts
- 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());
-
// kernel tracepoint probes
s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_TRACE)
->bind(new tracepoint_builder());
- // procfs parts
- 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());
-
// Kprobe based probe
s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_FUNCTION)
->bind(new kprobe_builder());
@@ -11906,7 +7994,10 @@ vector<derived_probe_group*>
all_session_groups(systemtap_session& s)
{
vector<derived_probe_group*> g;
-#define DOONE(x) if (s. x##_derived_probes) g.push_back (s. x##_derived_probes)
+
+#define DOONE(x) \
+ if (s. x##_derived_probes) \
+ g.push_back ((derived_probe_group*)(s. x##_derived_probes))
// Note that order *is* important here. We want to make sure we
// register (actually run) begin probes before any other probe type