diff options
author | Dave Brolley <brolley@redhat.com> | 2009-05-11 14:23:59 -0400 |
---|---|---|
committer | Dave Brolley <brolley@redhat.com> | 2009-05-11 14:23:59 -0400 |
commit | 7a0768a871545f8af96097de42837027922ddec1 (patch) | |
tree | b4dc0a456e43f368af26938aad7afa84e4279d90 /tapsets.cxx | |
parent | bbedb0a65e2f2ddee8f545e807310e7d1daed501 (diff) | |
parent | 5896cd059949413cf56678d7a7fa6c0788f576b5 (diff) | |
download | systemtap-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.cxx | 4325 |
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 |