diff options
author | dsmith <dsmith> | 2007-05-21 21:21:13 +0000 |
---|---|---|
committer | dsmith <dsmith> | 2007-05-21 21:21:13 +0000 |
commit | 2c384610cea3e62da8a4af676b5f8be523741b88 (patch) | |
tree | 3640552069c2ef7388a9a3c2202ccd1b9ecd8cbc /tapsets.cxx | |
parent | 2f675c1e854d1546ade5c29b3fb8ddf41349c5e0 (diff) | |
download | systemtap-steved-2c384610cea3e62da8a4af676b5f8be523741b88.tar.gz systemtap-steved-2c384610cea3e62da8a4af676b5f8be523741b88.tar.xz systemtap-steved-2c384610cea3e62da8a4af676b5f8be523741b88.zip |
2007-05-21 David Smith <dsmith@redhat.com>
PR 4446.
* elaborate.h (derived_probe::initialize_probe_context_vars): New
virtual function that will allow added context vars to be
initialized.
* translate.cxx (c_unparser::emit_common_header): Added
'mark_va_list'.
(c_unparser::emit_probe): Calls new function
initialize_probe_context_vars.
(translate_pass): Includes linux/marker.h if CONFIG_MARKERS is
defined.
* tapsets.cxx (struct dwarf_query): Split into base_query (which
contains most of the original code) and a much smaller
dwarf_query class.
(struct base_query): New class.
(dwarf_query::handle_query_module): New function.
(query_module): Moved code into dwarf_query::handle_query_module().
(mark_derived_probe): Adjusted for new kernel markers.
(mark_derived_probe_group): Ditto.
(mark_var_expanding_copy_visitor): Ditto.
(mark_var_expanding_copy_visitor::visit_target_symbol): Generates
code for new kernel markers.
(struct mark_query): New class.
(mark_query::handle_query_module): New function.
(mark_derived_probe::mark_derived_probe): Adjusted for new kernel
markers.
(mark_derived_probe::join_group): Ditto.
(mark_derived_probe::emit_probe_context_vars): Ditto.
(mark_derived_probe::parse_probe_sig): New function.
(mark_derived_probe::initialize_probe_context_vars): New function.
(mark_derived_probe::emit_module_decls): Adjust for new kernel markers.
(mark_derived_probe::emit_module_init): Ditto.
(mark_derived_probe::emit_module_exit): Ditto.
(struct mark_builder): Ditto.
(mark_builder::build): Ditto.
Diffstat (limited to 'tapsets.cxx')
-rw-r--r-- | tapsets.cxx | 970 |
1 files changed, 561 insertions, 409 deletions
diff --git a/tapsets.cxx b/tapsets.cxx index a2fb1622..d5590614 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1989,16 +1989,21 @@ public: // Helper struct to thread through the dwfl callbacks. -struct dwarf_query +struct base_query { - dwarf_query(systemtap_session & sess, - probe * base_probe, - probe_point * base_loc, - dwflpp & dw, - map<string, literal *> const & params, - vector<derived_probe *> & results); + base_query(systemtap_session & sess, + probe * base_probe, + probe_point * base_loc, + dwflpp & dw, + map<string, literal *> const & params, + vector<derived_probe *> & results); + virtual ~base_query() {} systemtap_session & sess; + probe * base_probe; + probe_point * base_loc; + dwflpp & dw; + vector<derived_probe *> & results; // Parameter extractors. static bool has_null_param(map<string, literal *> const & params, @@ -2010,8 +2015,85 @@ struct dwarf_query static bool get_number_param(map<string, literal *> const & params, string const & k, Dwarf_Addr & v); - // Result vector - vector<derived_probe *> & results; + // Extracted parameters. + bool has_kernel; + string module_val; // has_kernel => module_val = "kernel" + + virtual void handle_query_module() = 0; +}; + + +base_query::base_query(systemtap_session & sess, + probe * base_probe, + probe_point * base_loc, + dwflpp & dw, + map<string, literal *> const & params, + vector<derived_probe *> & results) + : sess(sess), base_probe(base_probe), base_loc(base_loc), dw(dw), + results(results) +{ + has_kernel = has_null_param(params, TOK_KERNEL); + if (has_kernel) + module_val = "kernel"; + else + { + bool has_module = get_string_param(params, TOK_MODULE, module_val); + assert (has_module); // no other options are possible by construction + } +} + +bool +base_query::has_null_param(map<string, literal *> const & params, + string const & k) +{ + map<string, literal *>::const_iterator i = params.find(k); + if (i != params.end() && i->second == NULL) + return true; + return false; +} + + +bool +base_query::get_string_param(map<string, literal *> const & params, + string const & k, string & v) +{ + return derived_probe_builder::get_param (params, k, v); +} + + +bool +base_query::get_number_param(map<string, literal *> const & params, + string const & k, long & v) +{ + int64_t value; + bool present = derived_probe_builder::get_param (params, k, value); + v = (long) value; + return present; +} + + +bool +base_query::get_number_param(map<string, literal *> const & params, + string const & k, Dwarf_Addr & v) +{ + int64_t value; + bool present = derived_probe_builder::get_param (params, k, value); + v = (Dwarf_Addr) value; + return present; +} + + +struct dwarf_query : public base_query +{ + dwarf_query(systemtap_session & sess, + probe * base_probe, + probe_point * base_loc, + dwflpp & dw, + map<string, literal *> const & params, + vector<derived_probe *> & results); + + virtual void handle_query_module(); + void add_probe_point(string const & funcname, char const * filename, int line, @@ -2030,8 +2112,6 @@ struct dwarf_query Dwarf_Addr addr); // Extracted parameters. - bool has_kernel; - string module_val; // has_kernel => module_val = "kernel" string function_val; bool has_function_str; @@ -2071,10 +2151,6 @@ struct dwarf_query map<Dwarf_Addr, func_info> filtered_functions; bool choose_next_line; Dwarf_Addr entrypc_for_next_line; - - probe * base_probe; - probe_point * base_loc; - dwflpp & dw; }; @@ -2107,69 +2183,18 @@ struct dwarf_builder: public derived_probe_builder vector<derived_probe *> & finished_results); }; -bool -dwarf_query::has_null_param(map<string, literal *> const & params, - string const & k) -{ - map<string, literal *>::const_iterator i = params.find(k); - if (i != params.end() && i->second == NULL) - return true; - return false; -} - -bool -dwarf_query::get_string_param(map<string, literal *> const & params, - string const & k, string & v) -{ - return derived_probe_builder::get_param (params, k, v); -} - -bool -dwarf_query::get_number_param(map<string, literal *> const & params, - string const & k, long & v) -{ - int64_t value; - bool present = derived_probe_builder::get_param (params, k, value); - v = (long) value; - return present; -} - -bool -dwarf_query::get_number_param(map<string, literal *> const & params, - string const & k, Dwarf_Addr & v) -{ - int64_t value; - bool present = derived_probe_builder::get_param (params, k, value); - v = (Dwarf_Addr) value; - return present; -} - - dwarf_query::dwarf_query(systemtap_session & sess, probe * base_probe, probe_point * base_loc, dwflpp & dw, map<string, literal *> const & params, vector<derived_probe *> & results) - : sess(sess), - results(results), - base_probe(base_probe), - base_loc(base_loc), - dw(dw) + : base_query(sess, base_probe, base_loc, dw, params, results) { // Reduce the query to more reasonable semantic values (booleans, // extracted strings, numbers, etc). - has_kernel = has_null_param(params, TOK_KERNEL); - if (has_kernel) - module_val = "kernel"; - else - { - bool has_module = get_string_param(params, TOK_MODULE, module_val); - assert (has_module); // no other options are possible by construction - } - has_function_str = get_string_param(params, TOK_FUNCTION, function_str_val); has_function_num = get_number_param(params, TOK_FUNCTION, function_num_val); @@ -2192,6 +2217,37 @@ dwarf_query::dwarf_query(systemtap_session & sess, void +dwarf_query::handle_query_module() +{ + if (has_function_num || has_statement_num) + { + // If we have module("foo").function(0xbeef) or + // module("foo").statement(0xbeef), the address is relative + // to the start of the module, so we seek the function + // number plus the module's bias. + + Dwarf_Addr addr; + if (has_function_num) + addr = function_num_val; + else + addr = statement_num_val; + + // NB: we don't need to add the module base address or bias + // value here (for reasons that may be coincidental). + dw.query_cu_containing_module_address(addr, this); + } + else + { + // Otherwise if we have a function("foo") or statement("foo") + // specifier, we have to scan over all the CUs looking for + // the function(s) in question + assert(has_function_str || has_statement_str); + dw.iterate_over_cus(&query_cu, this); + } +} + + +void dwarf_query::build_blacklist() { // FIXME: it would be nice if these blacklisted functions were pulled in @@ -2877,7 +2933,7 @@ query_module (Dwfl_Module *mod, Dwarf_Addr, void *arg) { - dwarf_query * q = static_cast<dwarf_query *>(arg); + base_query * q = static_cast<base_query *>(arg); try { @@ -2947,31 +3003,7 @@ query_module (Dwfl_Module *mod, << " (code " << elf_machine << ")" << "\n"; - if (q->has_function_num || q->has_statement_num) - { - // If we have module("foo").function(0xbeef) or - // module("foo").statement(0xbeef), the address is relative - // to the start of the module, so we seek the function - // number plus the module's bias. - - Dwarf_Addr addr; - if (q->has_function_num) - addr = q->function_num_val; - else - addr = q->statement_num_val; - - // NB: we don't need to add the module base address or bias - // value here (for reasons that may be coincidental). - q->dw.query_cu_containing_module_address(addr, q); - } - else - { - // Otherwise if we have a function("foo") or statement("foo") - // specifier, we have to scan over all the CUs looking for - // the function(s) in question - assert(q->has_function_str || q->has_statement_str); - q->dw.iterate_over_cus(&query_cu, q); - } + q->handle_query_module(); // If we know that there will be no more matches, abort early. if (q->dw.module_name_final_match(q->module_val)) @@ -4163,59 +4195,196 @@ profile_derived_probe_group::emit_module_exit (systemtap_session& s) // ------------------------------------------------------------------------ +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_sig, - uintptr_t address, const string& module, + const string& module, probe* base_probe); systemtap_session& sess; string probe_name, probe_sig; - uintptr_t address; string module; - string probe_sig_expanded; + vector <struct mark_arg *> mark_args; + bool target_symbol_seen; void join_group (systemtap_session& s); void emit_probe_context_vars (translator_output* o); + void initialize_probe_context_vars (translator_output* o); + + void parse_probe_sig (); }; struct mark_derived_probe_group: public generic_dpg<mark_derived_probe> { public: - void emit_module_decls (systemtap_session&) {} - void emit_module_init (systemtap_session&) {} - void emit_module_exit (systemtap_session&) {} + 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_copy_visitor: public var_expanding_copy_visitor { mark_var_expanding_copy_visitor(systemtap_session& s, - const string& ms, const string& pn): - sess (s), mark_signature (ms), probe_name (pn) {} + 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 mark_signature; string probe_name; + vector <struct mark_arg *> &mark_args; + bool target_symbol_seen; void visit_target_symbol (target_symbol* e); }; +struct mark_query: public base_query +{ + mark_query(systemtap_session & sess, + probe * base_probe, + probe_point * base_loc, + dwflpp & dw, + map<string, literal *> const & params, + vector<derived_probe *> & results); + + virtual void handle_query_module(); + + bool has_mark_str; + string mark_str_val; +}; + +mark_query::mark_query(systemtap_session & sess, + probe * base_probe, + probe_point * base_loc, + dwflpp & dw, + map<string, literal *> const & params, + vector<derived_probe *> & results) + : base_query(sess, base_probe, base_loc, dw, params, results) +{ + has_mark_str = get_string_param (params, "mark", mark_str_val); + assert (has_mark_str); +} + +struct markers_data +{ + string name; + string params; +}; + +void +mark_query::handle_query_module() +{ + GElf_Addr baseaddr; + Elf *elf = dwfl_module_getelf(dw.module, &baseaddr); + assert(elf); + + string section_name; + size_t shstrndx; + dw.dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); + + // Find markers string section ("__markers_strings") + Elf_Scn *scn = NULL; + Elf_Scn *markers_string_scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + // Handle the section if it is a string/progbits section. + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr != NULL && shdr->sh_type == SHT_PROGBITS) + { + section_name = elf_strptr (elf, shstrndx, shdr->sh_name); + if (section_name == "__markers_strings") + { + markers_string_scn = scn; + break; + } + } + } + + // If this module doesn't have a markers string section, just + // return. Code above this will report an error if necessary. + if (markers_string_scn == NULL) + return; + + // Get the string section data now. + Elf_Data *data = elf_getdata(markers_string_scn, NULL); + if (data == NULL) + throw semantic_error("no __markers_string data?"); + + // Process each marker. For each marker, there should be 2 strings + // in the __markers_string section: the marker name string and the + // marker parameter type list string. + size_t offset = 0; + vector<markers_data *> markers; + while (offset < data->d_size) + { + if (offset >= data->d_size) + throw semantic_error("bad __markers_string section?"); + string name = (char *)(data->d_buf) + offset; + offset += name.size() + 1; + + if (offset >= data->d_size) + throw semantic_error("bad __markers_string section?"); + string params = (char *)(data->d_buf) + offset; + offset += params.size() + 1; + + markers_data *m = new markers_data; + m->name = name; + m->params = params; + markers.push_back(m); + } + + // Search marker list for matching markers + for (size_t i = 0; i < markers.size(); i++) + { + const markers_data *m = markers.at(i); + + // Below, "rc" has negative polarity: zero iff matching. Also, + // we don't have to worry about the module not matching. If it + // didn't match, this function wouldn't get called. + int rc = fnmatch(mark_str_val.c_str(), m->name.c_str(), 0); + if (! rc) + { + derived_probe *dp + = new mark_derived_probe (sess, + m->name, m->params, + module_val, + base_probe); + results.push_back (dp); + } + } +} + void mark_var_expanding_copy_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") - throw semantic_error ("invalid target symbol for marker, $argN expected", e->tok); + throw semantic_error ("invalid target symbol for marker, $argN expected", + e->tok); 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_signature.size()) + + if (argnum < 1 || argnum > (int)mark_args.size()) throw semantic_error ("invalid marker argument number", e->tok); - char argtype = mark_signature[argnum-1]; + if (is_active_lvalue (e)) + throw semantic_error("write to marker parameter not permitted", e->tok); + + // Remember that we've seen a target variable. + target_symbol_seen = true; // Synthesize a function. functiondecl *fdecl = new functiondecl; @@ -4223,22 +4392,22 @@ mark_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) embeddedcode *ec = new embeddedcode; ec->tok = e->tok; - if (is_active_lvalue (e)) - throw semantic_error("write to marker parameter not permitted", e->tok); - string fname = string("_mark_tvar_get") + "_" + e->base_name.substr(1) + "_" + lex_cast<string>(tick++); - ec->code = string("THIS->__retvalue = CONTEXT->locals[0].") - + probe_name + string(".__mark_arg") - + lex_cast<string>(argnum) + string (";"); + if (mark_args[argnum-1]->stp_type == pe_long) + ec->code = string("THIS->__retvalue = CONTEXT->locals[0].") + + probe_name + string(".__mark_arg") + + lex_cast<string>(argnum) + string (";"); + else + ec->code = string("strlcpy (THIS->__retvalue, CONTEXT->locals[0].") + + probe_name + string(".__mark_arg") + + lex_cast<string>(argnum) + string (", MAXSTRINGLEN);"); ec->code += "/* pure */"; fdecl->name = fname; fdecl->body = ec; - fdecl->type = (argtype == 'N' ? pe_long : - argtype == 'S' ? pe_string : - pe_unknown); // cannot happen + fdecl->type = mark_args[argnum-1]->stp_type; sess.functions.push_back(fdecl); // Synthesize a functioncall. @@ -4254,18 +4423,19 @@ mark_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) mark_derived_probe::mark_derived_probe (systemtap_session &s, const string& p_n, const string& p_s, - uintptr_t a, const string& m, probe* base): derived_probe (base, 0), sess (s), probe_name (p_n), probe_sig (p_s), - address (a), module (m) + module (m), target_symbol_seen (false) { // create synthetic probe point probe_point* pp = new probe_point; probe_point::component* c; - if (module == "") c = new probe_point::component ("kernel"); - else c = new probe_point::component ("module", + if (module == "") + c = new probe_point::component ("kernel"); + else + c = new probe_point::component ("module", new literal_string (module)); pp->components.push_back (c); c = new probe_point::component ("mark", @@ -4274,244 +4444,339 @@ mark_derived_probe::mark_derived_probe (systemtap_session &s, this->locations.push_back (pp); // expand the signature string - for (unsigned i=0; i<probe_sig.length(); i++) - { - if (i > 0) - probe_sig_expanded += ", "; - switch (probe_sig[i]) - { - case 'N': probe_sig_expanded += "int64_t"; break; - case 'S': probe_sig_expanded += "const char *"; break; - default: - throw semantic_error ("unsupported probe signature " + probe_sig, - this->tok); - } - probe_sig_expanded += " arg" + lex_cast<string>(i+1); // arg1 ... - } + parse_probe_sig(); // Now make a local-variable-expanded copy of the probe body - mark_var_expanding_copy_visitor v (sess, probe_sig, name); + mark_var_expanding_copy_visitor v (sess, name, mark_args); require <block*> (&v, &(this->body), base->body); + target_symbol_seen = v.target_symbol_seen; if (sess.verbose > 1) - clog << "marker-based " << name << " address=0x" << hex << address << dec - << " signature=" << probe_sig << endl; + clog << "marker-based " << name << " signature=" << probe_sig << endl; } -void -mark_derived_probe::join_group (systemtap_session& s) +static int +skip_atoi(const char **s) { - throw semantic_error ("incomplete", this->tok); - - if (! s.mark_derived_probes) - s.mark_derived_probes = new mark_derived_probe_group (); - s.mark_derived_probes->enroll (this); + int i = 0; + while (isdigit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; } void -mark_derived_probe::emit_probe_context_vars (translator_output* o) +mark_derived_probe::parse_probe_sig() { - // Save incoming arguments - for (unsigned i=0; i<probe_sig.length(); i++) + const char *fmt = probe_sig.c_str(); + int qualifier; // 'h', 'l', or 'L' for integer fields + mark_arg *arg; + + for (; *fmt ; ++fmt) { - string localname = "__mark_arg" + lex_cast<string>(i+1); - switch (probe_sig[i]) + if (*fmt != '%') { - case 'S': o->newline() << "string_t " << localname << ";"; break; - case 'N': o->newline() << "int64_t " << localname << ";"; break; - } - } -} + /* Skip text */ + continue; + } +repeat: + ++fmt; -#if 0 -void -mark_derived_probe::emit_probe_entries (translator_output* o) -{ - assert (this->locations.size() == 1); + // skip conversion flags (if present) + switch (*fmt) + { + case '-': + case '+': + case ' ': + case '#': + case '0': + goto repeat; + } - o->newline() << "static void enter_" << name << " (" << probe_sig_expanded << ")"; - o->newline() << "{"; - o->newline(1) << "const char* probe_point = " - << lex_cast_qstring(* this->locations[0]) << ";"; - emit_probe_prologue (o, "STAP_SESSION_RUNNING"); + // skip minimum field witdh (if present) + if (isdigit(*fmt)) + skip_atoi(&fmt); - // Save incoming arguments - for (unsigned k=0; k<probe_sig.length(); k++) - { - string locals = "c->locals[0]." + name; - string localname = locals + ".__mark_arg" + lex_cast<string>(k+1); - string argname = "arg" + lex_cast<string>(k+1); - switch (probe_sig[k]) + // skip precision (if present) + if (*fmt == '.') { - case 'S': o->newline() << "strlcpy (" << localname << ", " << argname - << ", MAXSTRINGLEN);"; break; - // XXX: dupe with c_unparser::c_strcpy - case 'N': o->newline() << localname << " = " << argname << ";"; break; - } - } - - // NB: locals are initialized by probe function itself - o->newline() << name << " (c);"; + ++fmt; + if (isdigit(*fmt)) + skip_atoi(&fmt); + } - emit_probe_epilogue (o); - o->newline(-1) << "}"; -} + // 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; + arg->c_type = "void *"; + 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; -void -mark_derived_probe::emit_registrations_start (translator_output* o, - unsigned index) -{ - assert (this->locations.size() == 1); + default: + if (!*fmt) + --fmt; + continue; + } - o->newline() << "{"; - o->newline(1) << "void (**fn) (" << probe_sig_expanded << ") = (void *)" - << address << "UL;"; - - o->newline() << "#if __HAVE_ARCH_CMPXCHG"; - o->newline() << "unsigned long *fnpp = (unsigned long *) (void *) fn;"; - o->newline() << "unsigned long fnp = (unsigned long) (void *) & enter_" << name << ";"; - o->newline() << "unsigned long oldval = cmpxchg (fnpp, 0, fnp);"; - o->newline() << "if (oldval != 0) rc = 1;"; // XXX: could retry a few times - o->newline() << "#else"; - // XXX: need proper synchronization for concurrent registration attempts - o->newline() << "if (*fn == 0) *fn = & enter_" << name << ";"; - o->newline() << "#endif"; - o->newline() << "mb ();"; - o->newline() << "if (*fn != & enter_" << name << ") rc = 1;"; + arg = new mark_arg; + arg->str = false; + arg->stp_type = pe_long; + switch (qualifier) + { + case 'L': + arg->c_type = "long long"; + break; - o->newline(-1) << "}"; + case 'l': + arg->c_type = "long"; + break; + case 'h': + arg->c_type = "short"; + break; - // if one failed, must goto code (output by emit_registrations_end) - // that will roll back completed registations for this probe - o->newline() << "if (unlikely (rc)) {"; - o->newline(1) << "probe_point = " - << lex_cast_qstring (*this->locations[0]) << ";"; - if (index == 0) - o->newline() << "goto mark_error;"; - else - o->newline() << "goto unwind_mark_" << index - 1 << ";"; - o->newline(-1) << "}"; + default: + arg->c_type = "int"; + break; + } + mark_args.push_back(arg); + } } - void -mark_derived_probe::emit_registrations_end (translator_output* o, - unsigned index) +mark_derived_probe::join_group (systemtap_session& s) { - // if one failed, must roll back completed registations for this probe - o->newline(-1) << "unwind_mark_" << index << ":"; - o->indent(1); - emit_deregistrations (o); + if (! s.mark_derived_probes) + s.mark_derived_probes = new mark_derived_probe_group (); + s.mark_derived_probes->enroll (this); } void -mark_derived_probe::emit_deregistrations (translator_output * o) +mark_derived_probe::emit_probe_context_vars (translator_output* o) { - assert (this->locations.size() == 1); + // If we haven't seen a target symbol for this probe, quit. + if (! target_symbol_seen) + return; - o->newline() << "{"; - o->newline(1) << "void (**fn) (" << probe_sig_expanded << ") = (void *)" - << address << "UL;"; - o->newline() << "#if __HAVE_ARCH_CMPXCHG"; - o->newline() << "unsigned long *fnpp = (unsigned long *) (void *) fn;"; - o->newline() << "unsigned long fnp = (unsigned long) (void *) & enter_" << name << ";"; - o->newline() << "unsigned long oldval = cmpxchg (fnpp, fnp, 0);"; - o->newline() << "if (oldval != fnp) ;"; // XXX: should not happen - o->newline() << "#else"; - o->newline(0) << "*fn = 0;"; - o->newline() << "#endif"; - o->newline(-1) << "}"; + 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; + } + } } -#endif -#if 0 void -mark_derived_probe_group::emit_probes (translator_output* op, unparser* up) +mark_derived_probe::initialize_probe_context_vars (translator_output* o) { - for (unsigned i=0; i < probes.size(); i++) + // 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++) { - op->newline (); - up->emit_probe (probes[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);"; + // Need to report errors? + o->newline() << "deref_fault: ; }"; + break; + + default: + throw semantic_error ("cannot expand unknown type"); + break; + } } } void -mark_derived_probe_group::emit_module_init (translator_output* o) +mark_derived_probe_group::emit_module_decls (systemtap_session& s) { - if (probes.size () == 0) + if (probes.empty()) return; - // Output the mark probes create function - o->newline() << "static int register_mark_probes (void) {"; - o->indent(1); - o->newline() << "int rc = 0;"; - o->newline() << "const char *probe_point;"; + s.op->newline() << "/* ---- marker probes ---- */"; - for (unsigned i=0; i < probes.size (); i++) - probes[i]->emit_registrations_start (o, i); + // Warn of misconfigured kernels + s.op->newline() << "#if ! defined(CONFIG_MARKERS)"; + s.op->newline() << "#error \"Need CONFIG_MARKERS!\""; + s.op->newline() << "#endif"; + s.op->newline(); + + s.op->newline() << "struct stap_marker_probe {"; + s.op->newline(1) << "const char *name;"; + s.op->newline() << "const char *format;"; + s.op->newline() << "const char *pp;"; + s.op->newline() << "void (*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_sig) + << ","; + 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(); - o->newline() << "goto out;"; - o->newline(); - for (int i=probes.size() - 2; i >= 0; i--) - probes[i]->emit_registrations_end (o, i); + // Emit the marker callback function + s.op->newline(); + s.op->newline() << "static void enter_marker_probe (const struct __mark_marker_data *mdata, const char *fmt, ...) {"; + s.op->newline(1) << "struct stap_marker_probe *smp = (struct stap_marker_probe *)mdata->pdata;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); + s.op->newline() << "c->probe_point = smp->pp;"; - o->newline(); + s.op->newline() << "va_start(c->mark_va_list, fmt);"; + s.op->newline() << "(*smp->ph) (c);"; + s.op->newline() << "va_end(c->mark_va_list);"; + common_probe_entryfn_epilogue (s.op); + s.op->newline(-1) << "}"; - o->newline(-1) << "mark_error:"; - o->newline(1) << "if (unlikely (rc)) {"; - // In case it's just a lower-layer (kprobes) error that set rc but - // not session_state, do that here to prevent any other BEGIN probe - // from attempting to run. - o->newline(1) << "atomic_set (&session_state, STAP_SESSION_ERROR);"; - o->newline() << "_stp_error (\"mark probe %s registration failed, rc=%d\\n\", probe_point, rc);"; - o->newline(-1) << "}\n"; + return; +} - o->newline(-1) << "out:"; - o->newline(1) << "return rc;"; - o->newline(-1) << "}\n"; - // Output the mark probes destroy function - o->newline() << "static void unregister_mark_probes (void) {"; - o->indent(1); +void +mark_derived_probe_group::emit_module_init (systemtap_session &s) +{ + if (probes.size () == 0) + return; - for (unsigned i=0; i < probes.size (); i++) - { - probes[i]->emit_deregistrations (o); - emit_probe_timing(probes[i], o); - } + 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_set_probe(smp->name, smp->format, enter_marker_probe, smp) == 0);"; - o->newline(-1) << "}\n"; + 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_remove_probe(smp2->name);"; + 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 } -#endif -struct symboltable_extract +void +mark_derived_probe_group::emit_module_exit (systemtap_session& s) { - uintptr_t address; - string symbol; - string module; -}; - + if (probes.empty()) + return; -#define PROBE_SYMBOL_PREFIX "__systemtap_mark_" + 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_remove_probe(smp->name);"; + s.op->newline(-1) << "}"; // for loop +} struct mark_builder: public derived_probe_builder { private: - static const vector<symboltable_extract>* get_symbols (systemtap_session&); + dwflpp *kern_dw; public: - mark_builder() {} + mark_builder(): kern_dw(NULL) {} + ~mark_builder() { + // XXX: in practice, NOTREACHED + delete kern_dw; + } + + void build_no_more (systemtap_session &s) + { + if (kern_dw) + { + if (s.verbose > 3) + clog << "mark_builder releasing dwflpp" << endl; + delete kern_dw; + kern_dw = NULL; + } + } + void build(systemtap_session & sess, probe * base, probe_point * location, @@ -4520,78 +4785,13 @@ public: }; -// Until elfutils makes this straightforward, we kludge. -// See also translate.cxx:emit_symbol_data(). - -const vector<symboltable_extract>* -mark_builder::get_symbols (systemtap_session& sess) -{ - static vector<symboltable_extract>* syms = 0; - if (syms) return syms; // already computed - - syms = new vector<symboltable_extract>; - - // Process /proc/kallsyms - contains reliable module symbols - ifstream kallsyms ("/proc/kallsyms"); - while (! kallsyms.eof()) - { - string addr, type, sym, module; - kallsyms >> addr >> type >> sym; - kallsyms >> ws; - if (kallsyms.peek() == '[') - { - string bracketed; - kallsyms >> bracketed; - module = bracketed.substr (1, bracketed.length()-2); - } - else // kernel symbols come from /boot/System.map* - continue; - - if (type == "b" || type == "d") // static data/bss - { - symboltable_extract e; - e.address = strtoul (addr.c_str(), 0, 16); - e.symbol = sym; - e.module = module; - syms->push_back (e); - } - } - kallsyms.close (); - - // grab them kernel symbols - string smname = "/boot/System.map-"; - smname += sess.kernel_release; - ifstream systemmap (smname.c_str()); - while (! systemmap.eof()) - { - string addr, type, sym, module; - systemmap >> addr >> type >> sym; - module = ""; - - if (type == "b" || type == "d") // static data/bss - { - symboltable_extract e; - e.address = strtoul (addr.c_str(), 0, 16); - e.symbol = sym; - e.module = module; - syms->push_back (e); - } - } - systemmap.close (); - - return syms; -} - - void mark_builder::build(systemtap_session & sess, - probe * base, - probe_point * location, - std::map<std::string, literal *> const & parameters, - vector<derived_probe *> & finished_results) + probe * base, + probe_point * location, + std::map<std::string, literal *> const & parameters, + vector<derived_probe *> & finished_results) { - const vector<symboltable_extract>* syms = get_symbols (sess); - string param_module; bool has_module = get_param (parameters, "module", param_module); bool has_kernel = (parameters.find("kernel") != parameters.end()); @@ -4599,68 +4799,20 @@ mark_builder::build(systemtap_session & sess, if (! (has_module ^ has_kernel)) throw semantic_error ("need kernel or module() component", location->tok); - string param_probe; - bool has_probe = get_param (parameters, "mark", param_probe); - if (! has_probe) - throw semantic_error ("need mark() component", location->tok); - - string symbol_regex = PROBE_SYMBOL_PREFIX "([a-zA-Z0-9_]+)_([NS]*)\\.[0-9]+"; - // ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^ ^^^^^^ - // common prefix probe name types suffix - regex_t symbol_regex_t; - int rc = regcomp (& symbol_regex_t, symbol_regex.c_str(), REG_EXTENDED); - if (rc) - throw semantic_error ("regcomp '" + symbol_regex + "' failed"); - - // cout << "searching for " << symbol_regex << endl; + // NB: the kernel/user dwlfpp objects are long-lived. + // XXX: but they should be per-session, as this builder object + // may be reused if we try to cross-instrument multiple targets. - for (unsigned i=0; i<syms->size(); i++) + if (!kern_dw) { - regmatch_t match[3]; - const symboltable_extract& ext = syms->at(i); - const char* symstr = ext.symbol.c_str(); - - rc = regexec (& symbol_regex_t, symstr, 3, match, 0); - if (! rc) // match - { -#if 0 - cout << "match in " << symstr << ":" - << "[" << match[0].rm_so << "-" << match[0].rm_eo << "]," - << "[" << match[1].rm_so << "-" << match[1].rm_eo << "]," - << "[" << match[2].rm_so << "-" << match[2].rm_eo << "]" - << endl; -#endif - - string probe_name = string (symstr + match[1].rm_so, - (match[1].rm_eo - match[1].rm_so)); - string probe_sig = string (symstr + match[2].rm_so, - (match[2].rm_eo - match[2].rm_so)); - - // Below, "rc" has negative polarity: zero iff matching - rc = (has_module - ? fnmatch (param_module.c_str(), ext.module.c_str(), 0) - : (ext.module != "")); // kernel.* - rc |= fnmatch (param_probe.c_str(), probe_name.c_str(), 0); - - if (! rc) - { - // cout << "match (" << probe_name << "):" << probe_sig << endl; - - derived_probe *dp - = new mark_derived_probe (sess, - probe_name, probe_sig, - ext.address, - ext.module, - base); - finished_results.push_back (dp); - } - } + kern_dw = new dwflpp(sess); + assert(kern_dw); + kern_dw->setup(true); } - // cout << "done" << endl; + mark_query mq(sess, base, location, *kern_dw, parameters, finished_results); - // It's not a big deal if this is skipped due to an exception. - regfree (& symbol_regex_t); + kern_dw->iterate_over_modules(&query_module, &mq); } |