diff options
author | Josh Stone <jistone@redhat.com> | 2009-05-06 18:52:46 -0700 |
---|---|---|
committer | Josh Stone <jistone@redhat.com> | 2009-05-06 18:52:46 -0700 |
commit | 7a212aa8e893ad29acca3e80e1af01de0b894305 (patch) | |
tree | f3fa4fd435566e6fe150c977450cfcab4bea38b2 /tapsets.cxx | |
parent | 9004cc8cc0cf3b4d6be26471388d54fc4f364e74 (diff) | |
download | systemtap-steved-7a212aa8e893ad29acca3e80e1af01de0b894305.tar.gz systemtap-steved-7a212aa8e893ad29acca3e80e1af01de0b894305.tar.xz systemtap-steved-7a212aa8e893ad29acca3e80e1af01de0b894305.zip |
Separate the procfs tapset
Diffstat (limited to 'tapsets.cxx')
-rw-r--r-- | tapsets.cxx | 500 |
1 files changed, 1 insertions, 499 deletions
diff --git a/tapsets.cxx b/tapsets.cxx index e6d641bd..86b2aa53 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -4270,15 +4270,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 { @@ -8550,488 +8541,6 @@ kprobe_builder::build(systemtap_session & sess, // ------------------------------------------------------------------------ -// 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 // ------------------------------------------------------------------------ @@ -10987,6 +10496,7 @@ void register_standard_tapsets(systemtap_session & s) { register_tapset_been(s); + register_tapset_procfs(s); register_tapset_timers(s); s.pattern_root->bind("perfmon")->bind_str("counter") @@ -11061,14 +10571,6 @@ register_standard_tapsets(systemtap_session & s) 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()); |