diff options
Diffstat (limited to 'tapsets.cxx')
-rw-r--r-- | tapsets.cxx | 1049 |
1 files changed, 1 insertions, 1048 deletions
diff --git a/tapsets.cxx b/tapsets.cxx index 6a4d41b6..f0002073 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -6152,1016 +6152,6 @@ module_info::~module_info() } // ------------------------------------------------------------------------ -// utrace user-space probes -// ------------------------------------------------------------------------ - -static string TOK_BEGIN("begin"); -static string TOK_END("end"); -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); - - enable_task_finder(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 // ------------------------------------------------------------------------ @@ -8971,6 +7961,7 @@ register_standard_tapsets(systemtap_session & s) register_tapset_perfmon(s); register_tapset_procfs(s); register_tapset_timers(s); + register_tapset_utrace(s); // dwarf-based kprobe/uprobe parts @@ -8984,44 +7975,6 @@ 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 ()); - // kernel tracepoint probes s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_TRACE) ->bind(new tracepoint_builder()); |