summaryrefslogtreecommitdiffstats
path: root/tapsets.cxx
diff options
context:
space:
mode:
authorFrank Ch. Eigler <fche@elastic.org>2008-08-06 12:06:06 -0400
committerFrank Ch. Eigler <fche@elastic.org>2008-08-06 12:06:06 -0400
commit3c4371661f144c331dd55ee6be8dab57ec2323c8 (patch)
tree217ccf5864840f14670138b592d90eceacc75fa3 /tapsets.cxx
parent44ab6f3be72e7b5eeaa2514cea0553b87007ee9c (diff)
parent0317fad416059781b7a152296c1d8b5a012bf925 (diff)
downloadsystemtap-steved-3c4371661f144c331dd55ee6be8dab57ec2323c8.tar.gz
systemtap-steved-3c4371661f144c331dd55ee6be8dab57ec2323c8.tar.xz
systemtap-steved-3c4371661f144c331dd55ee6be8dab57ec2323c8.zip
Merge commit 'origin/master' into pr4225
* commit 'origin/master': Use relative instead of absolute line. (bug 6611) move post-0.7 news tidbit to the top Add test for $$vars, $$params, $$locals. typographical tweaks for embedded script code Add $$vars, $$parms, $$locals Rename $path to $pathname of syscall tapset for 2.6.27 Correct several tests for 2.6.27 c code generation: assert C indentation/nesting cancels out at appropriate points Tweak test_installcheck for helloworld.meta and traceio2.meta. Run both tests for installcheck tests. No need for random suffix file cmdline and sysinfo files in the Ensure that a systemtap server is available if 'server' is specified session.h (struct systemtap_session): Added itrace_derived_probe * syscalls2.stp: Add sys_unlinkat. Fix on_each_cpu() call for kernels >2.6.26. Remove unused STAPCONF_MODULE_NSECTIONS
Diffstat (limited to 'tapsets.cxx')
-rw-r--r--tapsets.cxx362
1 files changed, 361 insertions, 1 deletions
diff --git a/tapsets.cxx b/tapsets.cxx
index b9b4fcff..d06f7cea 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -2485,7 +2485,7 @@ struct dwarf_query : public base_query
// It arises because we sometimes try to fix up slightly-off
// .statement() probes (something we find out in fairly low-level).
//
-// An alternative would be to put some more intellgence into query_cu(),
+// An alternative would be to put some more intelligence into query_cu(),
// and have it print additional suggestions after finding that
// q->dw.iterate_over_srcfile_lines resulted in no new finished_results.
@@ -4285,6 +4285,84 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
return;
}
+ if (e->base_name == "$$vars"
+ || e->base_name == "$$parms"
+ || e->base_name == "$$locals")
+ {
+ Dwarf_Die *scopes;
+ if (dwarf_getscopes_die (scope_die, &scopes) == 0)
+ return;
+
+ target_symbol *tsym = new target_symbol;
+ print_format* pf = new print_format;
+
+ // Convert $$parms to sprintf of a list of parms and active local vars
+ // which we recursively evaluate
+ token* tmp_tok = new token;
+ tmp_tok->type = tok_identifier;
+ tmp_tok->content = "sprintf";
+ pf->tok = tmp_tok;
+ pf->print_to_stream = false;
+ pf->print_with_format = true;
+ pf->print_with_delim = false;
+ pf->print_with_newline = false;
+ pf->print_char = false;
+
+ Dwarf_Die result;
+ if (dwarf_child (&scopes[0], &result) == 0)
+ do
+ {
+ switch (dwarf_tag (&result))
+ {
+ case DW_TAG_variable:
+ if (e->base_name == "$$parms")
+ continue;
+ break;
+ case DW_TAG_formal_parameter:
+ if (e->base_name == "$$locals")
+ continue;
+ break;
+
+ default:
+ continue;
+ }
+
+ const char *diename = dwarf_diename (&result);
+ token* sym_tok = new token;
+ sym_tok->location = e->get_tok()->location;
+ sym_tok->type = tok_identifier;
+ sym_tok->content = diename;
+ tsym->tok = sym_tok;
+ tsym->base_name = "$";
+ tsym->base_name += diename;
+ Dwarf_Attribute attr_mem;
+
+ // Ignore any variable that isn't accessible.
+ // dwarf_attr_integrate is checked by literal_stmt_for_local
+ // dwarf_getlocation_addr is checked by translate_location
+ // but if those fail we cannot catch semantic_error.
+ if (dwarf_attr_integrate (&result, DW_AT_location, &attr_mem) != NULL)
+ {
+ Dwarf_Op *expr;
+ size_t len;
+ if (dwarf_getlocation_addr (&attr_mem, addr - q.dw.module_bias,
+ &expr, &len, 1) == 0)
+ continue;
+ this->visit_target_symbol(tsym);
+ pf->raw_components += diename;
+ pf->raw_components += "=%#x ";
+ pf->args.push_back(*(expression**)this->targets.top());
+ }
+ }
+ while (dwarf_siblingof (&result, &result) == 0);
+
+ pf->raw_components += "\\n";
+ pf->components = print_format::string_to_components(pf->raw_components);
+ provide <print_format*> (this, pf);
+
+ return;
+ }
+
// Synthesize a function.
functiondecl *fdecl = new functiondecl;
fdecl->tok = e->tok;
@@ -5376,6 +5454,280 @@ task_finder_derived_probe_group::emit_module_exit (systemtap_session& s)
s.op->newline() << "stap_stop_task_finder();";
}
+// ------------------------------------------------------------------------
+// itrace user-space probes
+// ------------------------------------------------------------------------
+
+
+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;
+ int single_step;
+
+ bool has_path = get_param (parameters, TOK_PROCESS, path);
+ bool has_pid = get_param (parameters, TOK_PROCESS, pid);
+ assert (has_path || has_pid);
+
+ single_step = 1;
+
+ // If we have a path, we need to validate it.
+ if (has_path)
+ {
+ string::size_type start_pos, end_pos;
+ string component;
+
+ // Make sure it starts with '/'.
+ if (path[0] != '/')
+ throw semantic_error ("process path must start with a '/'",
+ location->tok);
+
+ start_pos = 1; // get past the initial '/'
+ while ((end_pos = path.find('/', start_pos)) != string::npos)
+ {
+ component = path.substr(start_pos, end_pos - start_pos);
+ // Make sure it isn't empty.
+ if (component.size() == 0)
+ throw semantic_error ("process path component cannot be empty",
+ location->tok);
+ // Make sure it isn't relative.
+ else if (component == "." || component == "..")
+ throw semantic_error ("process 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 ("process path cannot end with a '/'", location->tok);
+ // Make sure it isn't relative.
+ else if (component == "." || component == "..")
+ throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok);
+ }
+
+ 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");
+ s.op->newline() << "c->probe_point = 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 task_struct *tsk, int register_p, int process_p, struct stap_task_finder_target *tgt) {";
+ s.op->indent(1);
+ s.op->newline() << "int rc = 0;";
+ s.op->newline() << "struct stap_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) << "}";
+
+ s.op->newline() << "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() << "/* ---- 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];";
+ 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
@@ -8723,6 +9075,13 @@ register_standard_tapsets(systemtap_session & s)
->bind(new utrace_builder ());
s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END)
->bind(new utrace_builder ());
+
+ // itrace user-space probes
+ s.pattern_root->bind_str(TOK_PROCESS)->bind("itrace")
+ ->bind(new itrace_builder ());
+ s.pattern_root->bind_num(TOK_PROCESS)->bind("itrace")
+ ->bind(new itrace_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)
@@ -8774,6 +9133,7 @@ all_session_groups(systemtap_session& s)
// "register" the dummy task_finder probe group after all probe
// groups that use the task_finder.
DOONE(utrace);
+ DOONE(itrace);
DOONE(task_finder);
#undef DOONE
return g;