diff options
Diffstat (limited to 'tapsets.cxx')
-rw-r--r-- | tapsets.cxx | 362 |
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; |