summaryrefslogtreecommitdiffstats
path: root/tapsets.cxx
diff options
context:
space:
mode:
authorJim Keniston <jkenisto@us.ibm.com>2009-03-23 15:51:58 -0700
committerJim Keniston <jkenisto@us.ibm.com>2009-03-23 15:51:58 -0700
commit1cd9c3ad40595180123083109e5b7d1230095f54 (patch)
treed1226de1275b40803f3e1c9d446232612b9a61a9 /tapsets.cxx
parentd8b7418ba4cf2bf2571f66a42517b9bced1b9132 (diff)
parentd4db5608dbc31868a2041f20ea3f473eef3e61fd (diff)
downloadsystemtap-steved-1cd9c3ad40595180123083109e5b7d1230095f54.tar.gz
systemtap-steved-1cd9c3ad40595180123083109e5b7d1230095f54.tar.xz
systemtap-steved-1cd9c3ad40595180123083109e5b7d1230095f54.zip
Merge branch 'master' of ssh://kenistoj@sources.redhat.com/git/systemtap
Diffstat (limited to 'tapsets.cxx')
-rw-r--r--tapsets.cxx285
1 files changed, 196 insertions, 89 deletions
diff --git a/tapsets.cxx b/tapsets.cxx
index b1d0b04e..e9ade595 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -18,6 +18,7 @@
#include "buildrun.h"
#include "dwarf_wrappers.h"
#include "auto_free.h"
+#include "hash.h"
#include <cstdlib>
#include <algorithm>
@@ -206,7 +207,9 @@ common_probe_entryfn_prologue (translator_output* o, string statestr,
o->newline() << "c = per_cpu_ptr (contexts, smp_processor_id());";
o->newline() << "if (atomic_inc_return (& c->busy) != 1) {";
- o->newline(1) << "atomic_inc (& skipped_count);";
+ o->newline(1) << "#if !INTERRUPTIBLE";
+ o->newline() << "atomic_inc (& skipped_count);";
+ o->newline() << "#endif";
o->newline() << "#ifdef STP_TIMING";
o->newline() << "atomic_inc (& skipped_count_reentrant);";
o->newline() << "#ifdef DEBUG_REENTRANCY";
@@ -3521,9 +3524,17 @@ dwarf_query::blacklisted_p(const string& funcname,
if (! (goodfn && goodfile))
{
- if (sess.verbose>1)
- clog << " skipping - blacklisted";
- return true;
+ if (sess.guru_mode)
+ {
+ if (sess.verbose>1)
+ clog << " guru mode enabled - ignoring blacklist";
+ }
+ else
+ {
+ if (sess.verbose>1)
+ clog << " skipping - blacklisted";
+ return true;
+ }
}
// This probe point is not blacklisted.
@@ -4842,18 +4853,31 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
}
catch (const semantic_error& er)
{
- // We suppress this error message, and pass the unresolved
- // target_symbol to the next pass. We hope that this value ends
- // up not being referenced after all, so it can be optimized out
- // quietly.
- provide (e);
- semantic_error* saveme = new semantic_error (er); // copy it
- saveme->tok1 = e->tok; // XXX: token not passed to q.dw code generation routines
- // NB: we can have multiple errors, since a $target variable
- // may be expanded in several different contexts:
- // function ("*") { $var }
- saveme->chain = e->saved_conversion_error;
- e->saved_conversion_error = saveme;
+ if (!q.sess.skip_badvars)
+ {
+ // We suppress this error message, and pass the unresolved
+ // target_symbol to the next pass. We hope that this value ends
+ // up not being referenced after all, so it can be optimized out
+ // quietly.
+ provide (e);
+ semantic_error* saveme = new semantic_error (er); // copy it
+ saveme->tok1 = e->tok; // XXX: token not passed to q.dw code generation routines
+ // NB: we can have multiple errors, since a $target variable
+ // may be expanded in several different contexts:
+ // function ("*") { $var }
+ saveme->chain = e->saved_conversion_error;
+ e->saved_conversion_error = saveme;
+ }
+ else
+ {
+ // Upon user request for ignoring context, the symbol is replaced
+ // with a literal 0 and a warning message displayed
+ literal_number* ln_zero = new literal_number (0);
+ ln_zero->tok = e->tok;
+ provide (ln_zero);
+ q.sess.print_warning ("Bad variable being substituted with literal 0",
+ e->tok);
+ }
delete fdecl;
delete ec;
return;
@@ -5004,7 +5028,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
// split the module string by ':' for alternatives
size_t mod_begin = mod_end + 1;
mod_end = e->module.find(':', mod_begin);
- string module = e->module.substr(mod_begin, mod_end);
+ string module = e->module.substr(mod_begin, mod_end - mod_begin);
// NB: This uses '/' to distinguish between kernel modules and userspace,
// which means that userspace modules won't get any PATH searching.
@@ -5046,7 +5070,8 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
// cast_op to the next pass. We hope that this value ends
// up not being referenced after all, so it can be optimized out
// quietly.
- semantic_error* er = new semantic_error ("type definition not found", e->tok);
+ string msg = "type definition '" + e->type + "' not found";
+ semantic_error* er = new semantic_error (msg, e->tok);
// NB: we can have multiple errors, since a @cast
// may be expanded in several different contexts:
// function ("*") { @cast(...) }
@@ -6227,6 +6252,9 @@ task_finder_derived_probe_group::emit_module_exit (systemtap_session& s)
// ------------------------------------------------------------------------
+static string TOK_INSN("insn");
+static string TOK_BLOCK("block");
+
struct itrace_derived_probe: public derived_probe
{
bool has_path;
@@ -6301,7 +6329,7 @@ struct itrace_builder: public derived_probe_builder
// XXX: PR 6445 needs !has_path && !has_pid support
assert (has_path || has_pid);
- single_step = 1;
+ single_step = ! has_null_param (parameters, TOK_BLOCK);
// If we have a path, we need to validate it.
if (has_path)
@@ -7159,10 +7187,8 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
// Emit a "fake" probe decl that is really a hook for to get
// our vm_callback called.
string path = it->first;
- s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA";
emit_vm_callback_probe_decl (s, true, path, (int64_t)0,
"__stp_tf_vm_cb");
- s.op->newline() << "#endif";
for (unsigned i = 0; i < it->second.size(); i++)
{
@@ -7180,10 +7206,8 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
{
// Emit a "fake" probe decl that is really a hook for to get
// our vm_callback called.
- s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA";
emit_vm_callback_probe_decl (s, false, "", it->first,
"__stp_tf_vm_cb");
- s.op->newline() << "#endif";
for (unsigned i = 0; i < it->second.size(); i++)
{
@@ -9221,10 +9245,10 @@ mark_builder::build(systemtap_session & sess,
struct tracepoint_arg
{
- string name, c_type;
- bool used, isptr;
+ string name, c_type, typecast;
+ bool usable, used, isptr;
Dwarf_Die type_die;
- tracepoint_arg(): used(false), isptr(false) {}
+ tracepoint_arg(): usable(false), used(false), isptr(false) {}
};
struct tracepoint_derived_probe: public derived_probe
@@ -9276,7 +9300,7 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
// search for a tracepoint parameter matching this name
tracepoint_arg *arg = NULL;
for (unsigned i = 0; i < args.size(); ++i)
- if (args[i].name == argname)
+ if (args[i].usable && args[i].name == argname)
{
arg = &args[i];
arg->used = true;
@@ -9324,6 +9348,9 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
if (lvalue && (!dw.sess.guru_mode || e->components.empty()))
throw semantic_error("write to tracepoint variable '" + e->base_name
+ "' not permitted", e->tok);
+ // XXX: if a struct/union arg is passed by value, then writing to its fields
+ // is also meaningless until you dereference past a pointer member. It's
+ // harder to detect and prevent that though...
if (e->components.empty())
{
@@ -9495,6 +9522,8 @@ tracepoint_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
for (unsigned i = 0; i < args.size(); ++i)
{
+ if (!args[i].usable)
+ continue;
if (i > 0)
pf->raw_components += " ";
pf->raw_components += args[i].name;
@@ -9577,32 +9606,39 @@ tracepoint_derived_probe::tracepoint_derived_probe (systemtap_session& s,
static bool
dwarf_type_name(Dwarf_Die& type_die, string& c_type)
{
- // if this die has a direct name, then we're done
- const char *diename = dwarf_diename_integrate(&type_die);
- if (diename != NULL)
+ // if we've gotten down to a basic type, then we're done
+ bool done = true;
+ switch (dwarf_tag(&type_die))
{
- switch (dwarf_tag(&type_die))
- {
- case DW_TAG_structure_type:
- c_type.append("struct ");
- break;
- case DW_TAG_union_type:
- c_type.append("union ");
- break;
- }
- c_type.append(diename);
+ case DW_TAG_structure_type:
+ c_type.append("struct ");
+ break;
+ case DW_TAG_union_type:
+ c_type.append("union ");
+ break;
+ case DW_TAG_typedef:
+ case DW_TAG_base_type:
+ break;
+ default:
+ done = false;
+ break;
+ }
+ if (done)
+ {
+ c_type.append(dwarf_diename_integrate(&type_die));
return true;
}
// otherwise, this die is a type modifier.
// recurse into the referent type
+ // if it can't be named, just call it "void"
Dwarf_Attribute subtype_attr;
Dwarf_Die subtype_die;
if (!dwarf_attr_integrate(&type_die, DW_AT_type, &subtype_attr)
|| !dwarf_formref_die(&subtype_attr, &subtype_die)
|| !dwarf_type_name(subtype_die, c_type))
- return false;
+ c_type = "void";
const char *suffix = NULL;
switch (dwarf_tag(&type_die))
@@ -9623,33 +9659,47 @@ dwarf_type_name(Dwarf_Die& type_die, string& c_type)
return false;
}
c_type.append(suffix);
+
+ // XXX HACK! The va_list isn't usable as found in the debuginfo...
+ if (c_type == "struct __va_list_tag*")
+ c_type = "va_list";
+
return true;
}
static bool
-resolve_tracepoint_arg_type(Dwarf_Die& type_die, bool& isptr)
+resolve_tracepoint_arg_type(tracepoint_arg& arg)
{
Dwarf_Attribute type_attr;
- switch (dwarf_tag(&type_die))
+ switch (dwarf_tag(&arg.type_die))
{
case DW_TAG_typedef:
case DW_TAG_const_type:
case DW_TAG_volatile_type:
// iterate on the referent type
- return (dwarf_attr_integrate(&type_die, DW_AT_type, &type_attr)
- && dwarf_formref_die(&type_attr, &type_die)
- && resolve_tracepoint_arg_type(type_die, isptr));
+ return (dwarf_attr_integrate(&arg.type_die, DW_AT_type, &type_attr)
+ && dwarf_formref_die(&type_attr, &arg.type_die)
+ && resolve_tracepoint_arg_type(arg));
case DW_TAG_base_type:
// base types will simply be treated as script longs
- isptr = false;
+ arg.isptr = false;
return true;
case DW_TAG_pointer_type:
- // pointers can be either script longs,
- // or dereferenced with their referent type
- isptr = true;
- return (dwarf_attr_integrate(&type_die, DW_AT_type, &type_attr)
- && dwarf_formref_die(&type_attr, &type_die));
+ // pointers can be treated as script longs,
+ // and if we know their type, they can also be dereferenced
+ if (dwarf_attr_integrate(&arg.type_die, DW_AT_type, &type_attr)
+ && dwarf_formref_die(&type_attr, &arg.type_die))
+ arg.isptr = true;
+ arg.typecast = "(intptr_t)";
+ return true;
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ // for structs/unions which are passed by value, we turn it into
+ // a pointer that can be dereferenced.
+ arg.isptr = true;
+ arg.typecast = "(intptr_t)&";
+ return true;
default:
// should we consider other types too?
return false;
@@ -9673,12 +9723,12 @@ tracepoint_derived_probe::build_args(dwflpp& dw, Dwarf_Die& func_die)
Dwarf_Attribute type_attr;
if (!dwarf_attr_integrate (&arg, DW_AT_type, &type_attr)
|| !dwarf_formref_die (&type_attr, &tparg.type_die)
- || !dwarf_type_name(tparg.type_die, tparg.c_type)
- || !resolve_tracepoint_arg_type(tparg.type_die, tparg.isptr))
+ || !dwarf_type_name(tparg.type_die, tparg.c_type))
throw semantic_error ("cannot get type of tracepoint '"
+ tracepoint_name + "' parameter '"
+ tparg.name + "'");
+ tparg.usable = resolve_tracepoint_arg_type(tparg);
args.push_back(tparg);
if (sess.verbose > 4)
clog << "found parameter for tracepoint '" << tracepoint_name
@@ -9691,8 +9741,9 @@ tracepoint_derived_probe::build_args(dwflpp& dw, Dwarf_Die& func_die)
void
tracepoint_derived_probe::printargs(std::ostream &o) const
{
- for (unsigned i = 0; i < args.size(); ++i)
- o << " $" << args[i].name << ":" << args[i].c_type;
+ for (unsigned i = 0; i < args.size(); ++i)
+ if (args[i].usable)
+ o << " $" << args[i].name << ":" << args[i].c_type;
}
void
@@ -9719,14 +9770,19 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s)
if (probes.empty())
return;
- s.op->newline() << "/* ---- tracepointer probes ---- */";
+ s.op->newline() << "/* ---- tracepoint probes ---- */";
+ s.op->newline();
for (unsigned i = 0; i < probes.size(); ++i)
{
tracepoint_derived_probe *p = probes[i];
- s.op->newline();
+
+ // emit a separate entry function for each probe, since tracepoints
+ // don't provide any sort of context pointer.
s.op->newline() << "#include <" << p->header << ">";
s.op->newline() << "static void enter_tracepoint_probe_" << i << "(";
+ if (p->args.size() == 0)
+ s.op->line() << "void";
for (unsigned j = 0; j < p->args.size(); ++j)
{
if (j > 0)
@@ -9745,15 +9801,45 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s)
{
s.op->newline() << "c->locals[0]." << p->name << ".__tracepoint_arg_"
<< p->args[j].name << " = (int64_t)";
- if (p->args[j].isptr)
- s.op->line() << "(intptr_t)";
+ s.op->line() << p->args[j].typecast;
s.op->line() << "__tracepoint_arg_" << p->args[j].name << ";";
}
s.op->newline() << p->name << " (c);";
common_probe_entryfn_epilogue (s.op);
s.op->newline(-1) << "}";
+
+ // emit normalized registration functions
+ s.op->newline() << "static int register_tracepoint_probe_" << i << "(void) {";
+ s.op->newline(1) << "return register_trace_" << p->tracepoint_name
+ << "(enter_tracepoint_probe_" << i << ");";
+ s.op->newline(-1) << "}";
+
+ // NB: we're not prepared to deal with unreg failures. However, failures
+ // can only occur if the tracepoint doesn't exist (yet?), or if we
+ // weren't even registered. The former should be OKed by the initial
+ // registration call, and the latter is safe to ignore.
+ s.op->newline() << "static void unregister_tracepoint_probe_" << i << "(void) {";
+ s.op->newline(1) << "(void) unregister_trace_" << p->tracepoint_name
+ << "(enter_tracepoint_probe_" << i << ");";
+ s.op->newline(-1) << "}";
s.op->newline();
}
+
+ // emit an array of registration functions for easy init/shutdown
+ s.op->newline() << "static struct stap_tracepoint_probe {";
+ s.op->newline(1) << "int (*reg)(void);";
+ s.op->newline(0) << "void (*unreg)(void);";
+ s.op->newline(-1) << "} stap_tracepoint_probes[] = {";
+ s.op->indent(1);
+ for (unsigned i = 0; i < probes.size(); ++i)
+ {
+ s.op->newline () << "{";
+ s.op->line() << " .reg=&register_tracepoint_probe_" << i << ",";
+ s.op->line() << " .unreg=&unregister_tracepoint_probe_" << i;
+ s.op->line() << " },";
+ }
+ s.op->newline(-1) << "};";
+ s.op->newline();
}
@@ -9764,28 +9850,14 @@ tracepoint_derived_probe_group::emit_module_init (systemtap_session &s)
return;
s.op->newline() << "/* init tracepoint probes */";
-
- // We can't use a simple runtime loop because the probe registration
- // functions are distinct inlines. Instead, this will generate nesting as
- // deep as the number of probe points. Gotos are also possible, but the end
- // result is the same.
-
- for (unsigned i = 0; i < probes.size(); ++i)
- {
- s.op->newline() << "if (!rc) {";
- s.op->newline(1) << "probe_point = "
- << lex_cast_qstring (*probes[i]->sole_location()) << ";";
- s.op->newline() << "rc = register_trace_" << probes[i]->tracepoint_name
- << "(enter_tracepoint_probe_" << i << ");";
- }
-
- for (unsigned i = probes.size() - 1; i < probes.size(); --i)
- {
- s.op->newline() << "if (rc)";
- s.op->newline(1) << "unregister_trace_" << probes[i]->tracepoint_name
- << "(enter_tracepoint_probe_" << i << ");";
- s.op->newline(-2) << "}";
- }
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(1) << "rc = stap_tracepoint_probes[i].reg();";
+ s.op->newline() << "if (rc) {";
+ s.op->newline(1) << "for (j=i-1; j>=0; j--)"; // partial rollback
+ s.op->newline(1) << "stap_tracepoint_probes[j].unreg();";
+ s.op->newline(-1) << "break;"; // don't attempt to register any more probes
+ s.op->newline(-1) << "}";
+ s.op->newline(-1) << "}";
// This would be technically proper (on those autoconf-detectable
// kernels that include this function in tracepoint.h), however we
@@ -9804,10 +9876,10 @@ tracepoint_derived_probe_group::emit_module_exit (systemtap_session& s)
if (probes.empty())
return;
- s.op->newline() << "/* deregister tracepointer probes */";
- for (unsigned i = 0; i < probes.size(); ++i)
- s.op->newline() << "unregister_trace_" << probes[i]->tracepoint_name
- << "(enter_tracepoint_probe_" << i << ");";
+ s.op->newline() << "/* deregister tracepoint probes */";
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
+ s.op->newline(1) << "stap_tracepoint_probes[i].unreg();";
+ s.op->indent(-1);
// Not necessary: see above.
@@ -9922,12 +9994,43 @@ tracepoint_builder::init_dw(systemtap_session& s)
if (dw != NULL)
return true;
+ if (s.use_cache)
+ {
+ // see if the cached module exists
+ find_tracequery_hash(s);
+ if (!s.tracequery_path.empty())
+ {
+ int fd = open(s.tracequery_path.c_str(), O_RDONLY);
+ if (fd != -1)
+ {
+ if (s.verbose > 2)
+ clog << "Pass 2: using cached " << s.tracequery_path << endl;
+
+ dw = new dwflpp(s);
+ dw->setup_user(s.tracequery_path);
+ close(fd);
+ return true;
+ }
+ }
+ }
+
+ // no cached module, time to make it
string tracequery_ko;
int rc = make_tracequery(s, tracequery_ko);
if (rc != 0)
return false;
- // TODO cache tracequery.ko
+ if (s.use_cache)
+ {
+ // try to save tracequery in the cache
+ if (s.verbose > 2)
+ clog << "Copying " << tracequery_ko
+ << " to " << s.tracequery_path << endl;
+ if (copy_file(tracequery_ko.c_str(),
+ s.tracequery_path.c_str()) != 0)
+ cerr << "Copy failed (\"" << tracequery_ko << "\" to \""
+ << s.tracequery_path << "\"): " << strerror(errno) << endl;
+ }
dw = new dwflpp(s);
dw->setup_user(tracequery_ko);
@@ -10744,9 +10847,13 @@ register_standard_tapsets(systemtap_session & s)
->bind(new utrace_builder ());
// itrace user-space probes
- s.pattern_root->bind_str(TOK_PROCESS)->bind("itrace")
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_INSN)
+ ->bind(new itrace_builder ());
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_INSN)
+ ->bind(new itrace_builder ());
+ s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)
->bind(new itrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind("itrace")
+ s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)
->bind(new itrace_builder ());
// marker-based parts