From 4176d5b1f4bf25adb8e44eaae9e6ab1de5a2c806 Mon Sep 17 00:00:00 2001 From: Eugeniy Meshcheryakov Date: Mon, 23 Feb 2009 14:53:24 +0100 Subject: Don't include unused libebl.h --- tapsets.cxx | 1 - 1 file changed, 1 deletion(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 78d5a5b3..959aa56b 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -41,7 +41,6 @@ extern "C" { #include #include #include -#include #include #include #include -- cgit From 3c1f71d54d487806d4dfde0421b43e95d3662ea5 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Mon, 23 Feb 2009 18:23:41 +0100 Subject: Check whether a die has any children before iterating over it. * tapsets.cxx (iterate_over_cu_labels): Check dwarf_child result. --- tapsets.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 78d5a5b3..5d9d062f 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1330,7 +1330,10 @@ struct dwflpp const char * sym = label_val.c_str(); Dwarf_Die die; - dwarf_child (cu, &die); + int res = dwarf_child (cu, &die); + if (res != 0) + return; // die without children, bail out. + static string function_name; do { -- cgit From 9e67aff9f4c269e0a56524c3f2fafaf8e038bda7 Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Mon, 23 Feb 2009 17:14:52 -0500 Subject: Improve static probe: c++ navigation, -l output. * tapsets.cxx (dwflpp::build): Improve c+ method navigation. Use .label for listing mode. * systemtap.base/static_uprobes.exp: Test multiple invocations of the same probe per block. (SW9770) --- tapsets.cxx | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 5d9d062f..77e2efcc 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1341,13 +1341,11 @@ struct dwflpp Dwarf_Attribute *attr = dwarf_attr (&die, DW_AT_name, &attr_mem); int tag = dwarf_tag(&die); const char *name = dwarf_formstring (attr); - if (name == NULL) - continue; - if (tag == DW_TAG_subprogram) + if (tag == DW_TAG_subprogram && name != 0) { function_name = name; } - else if (tag == DW_TAG_label + else if (tag == DW_TAG_label && name != 0 && ((strncmp(name, sym, strlen(sym)) == 0) || (name_has_wildcard (sym) && function_name_matches_pattern (name, sym)))) @@ -5727,7 +5725,7 @@ dwarf_builder::build(systemtap_session & sess, } } - if (probe_type == probes_and_dwarf) + if (probe_type == probes_and_dwarf && ! sess.listing_mode) { Elf_Data *pdata = elf_getdata_rawchunk (elf, shdr->sh_offset, shdr->sh_size, ELF_T_BYTE); assert (pdata != NULL); @@ -5751,17 +5749,22 @@ dwarf_builder::build(systemtap_session & sess, if (probe_scn_offset % (sizeof(__uint64_t))) probe_scn_offset += sizeof(__uint64_t) - (probe_scn_offset % sizeof(__uint64_t)); probe_arg = *((__uint64_t*)((char*)pdata->d_buf + probe_scn_offset)); - if (strcmp (location->components[1]->arg->tok->content.c_str(), probe_name.c_str()) == 0) - { - probe_found = true; - break; - } if (probe_scn_offset % (sizeof(__uint64_t)*2)) probe_scn_offset = (probe_scn_offset + sizeof(__uint64_t)*2) - (probe_scn_offset % (sizeof(__uint64_t)*2)); + if (strcmp (location->components[1]->arg->tok->content.c_str(), probe_name.c_str()) == 0) + probe_found = true; + else + continue; + const token* sv_tok = location->components[1]->arg->tok; + location->components[1]->functor = TOK_STATEMENT; + location->components[1]->arg = new literal_number((int)probe_arg); + location->components[1]->arg->tok = sv_tok; + ((literal_map_t&)parameters)[TOK_STATEMENT] = location->components[1]->arg; + dwarf_query q(sess, base, location, *dw, parameters, finished_results); + dw->query_modules(&q); } - location->components[1]->functor = TOK_STATEMENT; - location->components[1]->arg = new literal_number((int)probe_arg); - ((literal_map_t&)parameters)[TOK_STATEMENT] = location->components[1]->arg; + if (probe_found) + return; } if (probe_type == dwarf_no_probes || ! probe_found) -- cgit From bec508deffdb39affbd6e93a7ce1d2c92d653a12 Mon Sep 17 00:00:00 2001 From: Ananth N Mavinakayanahalli Date: Wed, 25 Feb 2009 15:48:50 +0530 Subject: PR9896: Fix SystemTap build on Ubuntu Intrepid. The gcc on Ubuntu doesn't like fprintf() without format arguments --- tapsets.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 77e2efcc..b2419b62 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2297,9 +2297,9 @@ struct dwflpp assert(memstream); fprintf(memstream, "{\n"); - fprintf(memstream, prelude.c_str()); + fprintf(memstream, "%s", prelude.c_str()); bool deref = c_emit_location (memstream, head, 1); - fprintf(memstream, postlude.c_str()); + fprintf(memstream, "%s", postlude.c_str()); fprintf(memstream, " goto out;\n"); // dummy use of deref_fault label, to disable warning if deref() not used -- cgit From 1324cc8267f44de856daa6aedd76d157e4259d28 Mon Sep 17 00:00:00 2001 From: Maynard Johnson Date: Tue, 3 Mar 2009 16:41:48 -0600 Subject: This patch updates the itrace code to support the new utrace interface. It also adds a private copy of access_process_vm to runtime/itrace.c since that function is not consistently exported by all distros. --- tapsets.cxx | 1 + 1 file changed, 1 insertion(+) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 74a22480..046ef0c0 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -6362,6 +6362,7 @@ itrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(); s.op->newline() << "/* ---- itrace probes ---- */"; + s.op->newline() << "#include \"task_finder.c\""; s.op->newline() << "struct stap_itrace_probe {"; s.op->indent(1); s.op->newline() << "struct stap_task_finder_target tgt;"; -- cgit From 9b753edaf92d9e73455ccea4334ab340616c8f93 Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Tue, 3 Mar 2009 17:55:37 -0500 Subject: Search for a label instead of an address for .so static probes. * tapsets.cxx (dwflpp::build): Use .label for .so instead of .statement(N) --- tapsets.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 046ef0c0..1c098425 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -5706,6 +5706,7 @@ dwarf_builder::build(systemtap_session & sess, size_t shstrndx; Elf_Scn *probe_scn = NULL; bool probe_found = false; + bool dynamic = (dwfl_module_relocations (dw->module) == 1); dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); GElf_Shdr *shdr = NULL; @@ -5723,8 +5724,10 @@ dwarf_builder::build(systemtap_session & sess, break; } } + if (dynamic || sess.listing_mode) + probe_type = dwarf_no_probes; - if (probe_type == probes_and_dwarf && ! sess.listing_mode) + if (probe_type == probes_and_dwarf) { Elf_Data *pdata = elf_getdata_rawchunk (elf, shdr->sh_offset, shdr->sh_size, ELF_T_BYTE); assert (pdata != NULL); -- cgit From dd22832afe6c337eb020001834266ad1e7678b2c Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 4 Mar 2009 18:32:54 -0800 Subject: Make session.module_cache init more consistently We used to check & init module_cache in a few inconsistent places. Now it is always handled in dwflpp::setup_user/setup_kernel. * tapsets.cxx (dwflpp::setup_user): add module_cache check (dwarf_builder::build): remove module_cache check (dwarf_cast_expanding_visitor::visit_cast_op): ditto --- tapsets.cxx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 1c098425..7a321dce 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -958,6 +958,9 @@ struct dwflpp void setup_user(string module_name, bool debuginfo_needed = true) { + if (! sess.module_cache) + sess.module_cache = new module_cache (); + static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build"; static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); // NB: kernel_build_tree doesn't enter into this, as it's for @@ -4993,9 +4996,6 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) if (e->module.empty()) e->module = "kernel"; // "*" may also be reasonable to search all kernel modules - if (! s.module_cache) - s.module_cache = new module_cache (); - string code; exp_type type = pe_long; try @@ -5655,10 +5655,6 @@ dwarf_builder::build(systemtap_session & sess, dwflpp* dw = 0; - if (! sess.module_cache) - sess.module_cache = new module_cache (); - - string module_name; if (has_null_param (parameters, TOK_KERNEL) || get_param (parameters, TOK_MODULE, module_name)) -- cgit From 2da9cedbf2a1916107fe829692af5113646a894d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 4 Mar 2009 18:51:28 -0800 Subject: Make iterate_over_functions work with base_querys * tapsets.cxx (dwflpp::iterate_over_functions): Change arg from void* to base_query*, and add explicit function-search parameters. (query_cu): update caller (query_dwarf_func): update callback signature (Note: instead of passing around callback functions, it might be nicer to use a virtual method in base_query...) --- tapsets.cxx | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 7a321dce..834aa06a 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1193,8 +1193,9 @@ struct dwflpp return DWARF_CB_OK; } - int iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg), - void * data); + int iterate_over_functions (int (* callback)(Dwarf_Die * func, base_query * q), + base_query * q, const string& function, + bool has_statement_num=false); int iterate_over_globals (int (* callback)(Dwarf_Die *, void *), void * data); @@ -2937,13 +2938,13 @@ dwflpp::iterate_over_globals (int (* callback)(Dwarf_Die *, void *), } int -dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg), - void * data) +dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, base_query * q), + base_query * q, const string& function, + bool has_statement_num) { int rc = DWARF_CB_OK; assert (module); assert (cu); - dwarf_query * q = static_cast(data); string key = module_name + ":" + cu_name; cu_function_cache_t *v = cu_function_cache[key]; @@ -2956,13 +2957,13 @@ dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg), clog << "function cache " << key << " size " << v->size() << endl; } - string subkey = q->function; + string subkey = function; if (v->find(subkey) != v->end()) { Dwarf_Die die = v->find(subkey)->second; if (q->sess.verbose > 4) clog << "function cache " << key << " hit " << subkey << endl; - return (*callback)(& die, data); + return (*callback)(& die, q); } else if (name_has_wildcard (subkey)) { @@ -2976,17 +2977,17 @@ dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg), if (q->sess.verbose > 4) clog << "function cache " << key << " match " << func_name << " vs " << subkey << endl; - rc = (*callback)(& die, data); + rc = (*callback)(& die, q); if (rc != DWARF_CB_OK) break; } } } - else if (q->has_statement_num) // searching all for kernel.statement + else if (has_statement_num) // searching all for kernel.statement { for (cu_function_cache_t::iterator it = v->begin(); it != v->end(); it++) { Dwarf_Die die = it->second; - rc = (*callback)(& die, data); + rc = (*callback)(& die, q); if (rc != DWARF_CB_OK) break; } } @@ -3876,9 +3877,9 @@ query_dwarf_inline_instance (Dwarf_Die * die, void * arg) } static int -query_dwarf_func (Dwarf_Die * func, void * arg) +query_dwarf_func (Dwarf_Die * func, base_query * bq) { - dwarf_query * q = static_cast(arg); + dwarf_query * q = static_cast(bq); try { @@ -3892,7 +3893,7 @@ query_dwarf_func (Dwarf_Die * func, void * arg) if (q->sess.verbose>3) clog << "checking instances of inline " << q->dw.function_name << "\n"; - q->dw.iterate_over_inline_instances (query_dwarf_inline_instance, arg); + q->dw.iterate_over_inline_instances (query_dwarf_inline_instance, q); if (q->dw.function_name_final_match (q->function)) return DWARF_CB_ABORT; @@ -4026,7 +4027,9 @@ query_cu (Dwarf_Die * cudie, void * arg) // Pick up [entrypc, name, DIE] tuples for all the functions // matching the query, and fill in the prologue endings of them // all in a single pass. - int rc = q->dw.iterate_over_functions (query_dwarf_func, q); + int rc = q->dw.iterate_over_functions (query_dwarf_func, q, + q->function, + q->has_statement_num); if (rc != DWARF_CB_OK) q->query_done = true; -- cgit From 0a6f5a3f0c2ecfb8b4a416dd07d5b976daf79551 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 4 Mar 2009 19:32:25 -0800 Subject: Build tracequery to scan for tracepoints * session.h (systemtap_session): add tracepoint_derived_probes * buildrun.cxx (make_tracequery): New - builds a kernel module that hijacks the tracepoint declarations, so we can query debuginfo. * buildrun.h: declare above * tapsets.cxx (tracepoint_builder): New builder for tracepoint probes. For now it just handles the initialization to build the tracequery kernel module. --- tapsets.cxx | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 834aa06a..6693e9c3 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -15,6 +15,7 @@ #include "translate.h" #include "session.h" #include "util.h" +#include "buildrun.h" #include "dwarf_wrappers.h" #include "auto_free.h" @@ -465,6 +466,7 @@ static string TOK_STATEMENT("statement"); static string TOK_ABSOLUTE("absolute"); static string TOK_PROCESS("process"); static string TOK_MARK("mark"); +static string TOK_TRACE("trace"); static string TOK_LABEL("label"); // Can we handle this query with just symbol-table info? @@ -9200,6 +9202,81 @@ mark_builder::build(systemtap_session & sess, +// ------------------------------------------------------------------------ +// statically inserted kernel-tracepoint derived probes +// ------------------------------------------------------------------------ + + +struct tracepoint_derived_probe: public derived_probe +{ + // TODO +}; + + +struct tracepoint_derived_probe_group: public generic_dpg +{ + // TODO +}; + + +struct tracepoint_builder: public derived_probe_builder +{ +private: + dwflpp *dw; + bool init_dw(systemtap_session& s); + +public: + tracepoint_builder(): dw(0) {} + ~tracepoint_builder() { delete dw; } + + void build_no_more (systemtap_session& s) + { + if (dw && s.verbose > 3) + clog << "tracepoint_builder releasing dwflpp" << endl; + delete dw; + dw = NULL; + } + + void build(systemtap_session& s, + probe *base, probe_point *location, + literal_map_t const& parameters, + vector& finished_results); +}; + + +bool +tracepoint_builder::init_dw(systemtap_session& s) +{ + if (dw != NULL) + return true; + + string tracequery_ko; + int rc = make_tracequery(s, tracequery_ko); + if (rc != 0) + return false; + + // TODO cache tracequery.ko + + dw = new dwflpp(s); + dw->setup_user(tracequery_ko); + return true; +} + + +void +tracepoint_builder::build(systemtap_session& s, + probe *base, probe_point *location, + literal_map_t const& parameters, + vector& finished_results) +{ + if (!init_dw(s)) + return; + + // TODO run a query to match tracepoint locations +} + + + // ------------------------------------------------------------------------ // hrtimer derived probes // ------------------------------------------------------------------------ @@ -10002,6 +10079,10 @@ register_standard_tapsets(systemtap_session & s) s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK)->bind_str(TOK_FORMAT) ->bind(new mark_builder()); + // kernel tracepoint probes + 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) @@ -10030,6 +10111,7 @@ all_session_groups(systemtap_session& s) DOONE(timer); DOONE(profile); DOONE(mark); + DOONE(tracepoint); DOONE(hrtimer); DOONE(perfmon); DOONE(procfs); -- cgit From 75ead1f7f65c280a7a068e562dbb7b751f1f0de4 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 4 Mar 2009 19:56:02 -0800 Subject: Scan tracequery.ko for tracepoints * tapsets.cxx (tracepoint_query): Iterate over the modules, CUs, and functions in tracequery.ko looking for our hijacked tracepoint declarations. (tracepoint_builder::build): Run a tracepoint_query --- tapsets.cxx | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 6693e9c3..adda3d19 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -9219,6 +9219,80 @@ struct tracepoint_derived_probe_group: public generic_dpg & results): + base_query(dw, "*"), tracepoint(tracepoint), + base_probe(base_probe), base_loc(base_loc), + results(results) {} + + const string& tracepoint; + + probe * base_probe; + probe_point * base_loc; + vector & results; + + void handle_query_module(); + int handle_query_cu(Dwarf_Die * cudie); + int handle_query_func(Dwarf_Die * func); + + static int tracepoint_query_cu (Dwarf_Die * cudie, void * arg); + static int tracepoint_query_func (Dwarf_Die * func, base_query * query); +}; + + +void +tracepoint_query::handle_query_module() +{ + // look for the tracepoints in each CU + dw.iterate_over_cus(tracepoint_query_cu, this); +} + + +int +tracepoint_query::handle_query_cu(Dwarf_Die * cudie) +{ + dw.focus_on_cu (cudie); + + // look at each function to see if it's a tracepoint + string function = "stapprobe_" + tracepoint; + return dw.iterate_over_functions (tracepoint_query_func, this, function); +} + + +int +tracepoint_query::handle_query_func(Dwarf_Die * func) +{ + dw.focus_on_function (func); + + assert(dw.function_name.compare(0, 10, "stapprobe_") == 0); + string tracepoint_instance = dw.function_name.substr(10); + // TODO build a tracepoint_derived_probe + clog << "DEBUG: found a tracepoint: " << tracepoint_instance << endl; + return DWARF_CB_OK; +} + + +int +tracepoint_query::tracepoint_query_cu (Dwarf_Die * cudie, void * arg) +{ + tracepoint_query * q = static_cast(arg); + if (pending_interrupts) return DWARF_CB_ABORT; + return q->handle_query_cu(cudie); +} + + +int +tracepoint_query::tracepoint_query_func (Dwarf_Die * func, base_query * query) +{ + tracepoint_query * q = static_cast(query); + if (pending_interrupts) return DWARF_CB_ABORT; + return q->handle_query_func(func); +} + + struct tracepoint_builder: public derived_probe_builder { private: @@ -9272,7 +9346,11 @@ tracepoint_builder::build(systemtap_session& s, if (!init_dw(s)) return; - // TODO run a query to match tracepoint locations + string tracepoint; + assert(get_param (parameters, TOK_TRACE, tracepoint)); + + tracepoint_query q(*dw, tracepoint, base, location, finished_results); + dw->query_modules(&q); } -- cgit From 79189b84b112484901e5ee6b84a334da24791128 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 4 Mar 2009 20:17:38 -0800 Subject: Build skeleton tracepoint probes * tapsets.cxx (tracepoint_derived_probe): Create a skeleton probe (tracepoint_derived_probe_group): Create a skeleton group (tracepoint_query::handle_query_func): build a probe --- tapsets.cxx | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 4 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index adda3d19..f7bba968 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -9209,16 +9209,89 @@ mark_builder::build(systemtap_session & sess, struct tracepoint_derived_probe: public derived_probe { - // TODO + tracepoint_derived_probe (systemtap_session& s, + dwflpp& dw, Dwarf_Die& func_die, + const string& tracepoint_name, + probe* base_probe, probe_point* location); + + systemtap_session& sess; + string tracepoint_name; + + void join_group (systemtap_session& s); }; struct tracepoint_derived_probe_group: public generic_dpg { - // TODO + void emit_module_decls (systemtap_session& s); + void emit_module_init (systemtap_session& s); + void emit_module_exit (systemtap_session& s); }; +tracepoint_derived_probe::tracepoint_derived_probe (systemtap_session& s, + dwflpp& dw, Dwarf_Die& func_die, + const string& tracepoint_name, + probe* base, probe_point* loc): + derived_probe (base, new probe_point(*loc) /* .components soon rewritten */), + sess (s), tracepoint_name (tracepoint_name) +{ + // create synthetic probe point name; preserve condition + vector comps; + comps.push_back (new probe_point::component (TOK_KERNEL)); + comps.push_back (new probe_point::component (TOK_TRACE, new literal_string (tracepoint_name))); + this->sole_location()->components = comps; + + if (sess.verbose > 2) + clog << "tracepoint-based " << name << " tracepoint='" << tracepoint_name + << "'" << endl; +} + + +void +tracepoint_derived_probe::join_group (systemtap_session& s) +{ + if (! s.tracepoint_derived_probes) + s.tracepoint_derived_probes = new tracepoint_derived_probe_group (); + s.tracepoint_derived_probes->enroll (this); +} + + +void +tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s) +{ + if (probes.empty()) + return; + + s.op->newline() << "/* ---- tracepointer probes ---- */"; + + // TODO +} + + +void +tracepoint_derived_probe_group::emit_module_init (systemtap_session &s) +{ + if (probes.size () == 0) + return; + + s.op->newline() << "/* init tracepoint probes */"; + + // TODO +} + + +void +tracepoint_derived_probe_group::emit_module_exit (systemtap_session& s) +{ + if (probes.empty()) + return; + + s.op->newline() << "/* deregister tracepointer probes */"; + // TODO +} + + struct tracepoint_query : public base_query { tracepoint_query(dwflpp & dw, const string & tracepoint, @@ -9269,8 +9342,10 @@ tracepoint_query::handle_query_func(Dwarf_Die * func) assert(dw.function_name.compare(0, 10, "stapprobe_") == 0); string tracepoint_instance = dw.function_name.substr(10); - // TODO build a tracepoint_derived_probe - clog << "DEBUG: found a tracepoint: " << tracepoint_instance << endl; + derived_probe *dp = new tracepoint_derived_probe (dw.sess, dw, *func, + tracepoint_instance, + base_probe, base_loc); + results.push_back (dp); return DWARF_CB_OK; } -- cgit From 6fb70fb7915c3f5f7352e5393efb859b70e6f3fc Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 4 Mar 2009 20:32:22 -0800 Subject: Emit code to hook up tracepoint probes * tapsets.cxx (tracepoint_arg): New (tracepoint_derived_probe): Add declaring header name and arg vector (dwarf_type_name): Build a type string for a given type DIE (tracepoint_derived_probe::build_args): Scan the function DIE for the name and type of formal parameters required by the tracepoint. (tracepoint_derived_probe::tracepoint_derived_probe): Call build_args and determine the relevant header to include. (tracepoint_derived_probe_group::emit_module_decls): For each tracepoint, include its header and declare a probe entry point with the right function signature. (tracepoint_derived_probe_group::emit_module_init): Call the registration for each tracepoint, and handle error unwinding. (tracepoint_derived_probe_group::emit_module_exit): Unregister each. --- tapsets.cxx | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 157 insertions(+), 4 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index f7bba968..7c054411 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -9206,6 +9206,10 @@ mark_builder::build(systemtap_session & sess, // statically inserted kernel-tracepoint derived probes // ------------------------------------------------------------------------ +struct tracepoint_arg +{ + string name, c_type; +}; struct tracepoint_derived_probe: public derived_probe { @@ -9215,8 +9219,10 @@ struct tracepoint_derived_probe: public derived_probe probe* base_probe, probe_point* location); systemtap_session& sess; - string tracepoint_name; + string tracepoint_name, header; + vector args; + void build_args(dwflpp& dw, Dwarf_Die& func_die); void join_group (systemtap_session& s); }; @@ -9242,12 +9248,116 @@ tracepoint_derived_probe::tracepoint_derived_probe (systemtap_session& s, comps.push_back (new probe_point::component (TOK_TRACE, new literal_string (tracepoint_name))); this->sole_location()->components = comps; + // fill out the available arguments in this tracepoint + build_args(dw, func_die); + + // determine which header defined this tracepoint + string decl_file = dwarf_decl_file(&func_die); + size_t header_pos = decl_file.rfind("trace/"); + if (header_pos == string::npos) + throw semantic_error ("cannot parse header location for tracepoint '" + + tracepoint_name + "' in '" + + decl_file + "'"); + header = decl_file.substr(header_pos); + + // tracepoints from FOO_event_types.h should really be included from FOO.h + // XXX can dwarf tell us the include hierarchy? it would be better to + // ... walk up to see which one was directly included by tracequery.c + header_pos = header.find("_event_types"); + if (header_pos != string::npos) + header.erase(header_pos, 12); + if (sess.verbose > 2) clog << "tracepoint-based " << name << " tracepoint='" << tracepoint_name << "'" << endl; } +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) + { + 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); + return true; + } + + // otherwise, this die is a type modifier. + + // recurse into the referent type + 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; + + const char *suffix = NULL; + switch (dwarf_tag(&type_die)) + { + case DW_TAG_pointer_type: + suffix = "*"; + break; + case DW_TAG_array_type: + suffix = "[]"; + break; + case DW_TAG_const_type: + suffix = " const"; + break; + case DW_TAG_volatile_type: + suffix = " volatile"; + break; + default: + return false; + } + c_type.append(suffix); + return true; +} + + +void +tracepoint_derived_probe::build_args(dwflpp& dw, Dwarf_Die& func_die) +{ + Dwarf_Die arg; + if (dwarf_child(&func_die, &arg) == 0) + do + if (dwarf_tag(&arg) == DW_TAG_formal_parameter) + { + // build a tracepoint_arg for this parameter + tracepoint_arg tparg; + tparg.name = dwarf_diename_integrate(&arg); + + // read the type of this parameter + Dwarf_Attribute type_attr; + Dwarf_Die type_die; + if (!dwarf_attr_integrate (&arg, DW_AT_type, &type_attr) + || !dwarf_formref_die (&type_attr, &type_die) + || !dwarf_type_name(type_die, tparg.c_type)) + throw semantic_error ("cannot get type of tracepoint '" + + tracepoint_name + "' parameter '" + + tparg.name + "'"); + + args.push_back(tparg); + if (sess.verbose > 4) + clog << "found parameter for tracepoint '" << tracepoint_name + << "': type:'" << tparg.c_type + << "' name:'" << tparg.name << "'" << endl; + } + while (dwarf_siblingof(&arg, &arg) == 0); +} + + void tracepoint_derived_probe::join_group (systemtap_session& s) { @@ -9265,7 +9375,28 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "/* ---- tracepointer probes ---- */"; - // TODO + for (unsigned i = 0; i < probes.size(); ++i) + { + tracepoint_derived_probe *p = probes[i]; + s.op->newline(); + s.op->newline() << "#include <" << p->header << ">"; + s.op->newline() << "static void enter_tracepoint_probe_" << i << "("; + for (unsigned j = 0; j < p->args.size(); ++j) + { + if (j > 0) + s.op->line() << ", "; + s.op->line() << p->args[j].c_type << " __tracepoint_arg_" << p->args[j].name; + } + s.op->line() << ") {"; + s.op->indent(1); + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); + s.op->newline() << "c->probe_point = " + << lex_cast_qstring (*p->sole_location()) << ";"; + s.op->newline() << p->name << " (c);"; + common_probe_entryfn_epilogue (s.op); + s.op->newline(-1) << "}"; + s.op->newline(); + } } @@ -9277,7 +9408,27 @@ tracepoint_derived_probe_group::emit_module_init (systemtap_session &s) s.op->newline() << "/* init tracepoint probes */"; - // TODO + // 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) << "}"; + } } @@ -9288,7 +9439,9 @@ tracepoint_derived_probe_group::emit_module_exit (systemtap_session& s) return; s.op->newline() << "/* deregister tracepointer probes */"; - // TODO + for (unsigned i = 0; i < probes.size(); ++i) + s.op->newline() << "unregister_trace_" << probes[i]->tracepoint_name + << "(enter_tracepoint_probe_" << i << ");"; } -- cgit From f8a968bccd1e71f2e8f486e60ff95a4d718a6332 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 4 Mar 2009 21:07:54 -0800 Subject: Enable tracepoint target variables This uses a similar mechanism as marker probes for storing target variables in locals of the probe body. * tapsets.cxx (tracepoint_arg): Add fields to help $target access. (tracepoint_var_expanding_visitor): Expand code to access target variables - a $target for each tracepoint parameter, as well as the special $$name and $$vars. (tracepoint_derived_probe::tracepoint_derived_probe): Expand targets (resolve_tracepoint_arg_type): Determine if a parameter is a type that we can dereference, and store the underlying type. (tracepoint_derived_probe::build_args): Resolve the types. (tracepoint_derived_probe::emit_probe_context_vars): Emit $target placeholders into the locals of the probe body. (tracepoint_derived_probe_group::emit_module_decls): Initialize $targets from the entry point parameters. --- tapsets.cxx | 341 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 338 insertions(+), 3 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 7c054411..5aa67e4d 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -9209,6 +9209,9 @@ mark_builder::build(systemtap_session & sess, struct tracepoint_arg { string name, c_type; + bool used, isptr; + Dwarf_Die type_die; + tracepoint_arg(): used(false), isptr(false) {} }; struct tracepoint_derived_probe: public derived_probe @@ -9224,6 +9227,7 @@ struct tracepoint_derived_probe: public derived_probe void build_args(dwflpp& dw, Dwarf_Die& func_die); void join_group (systemtap_session& s); + void emit_probe_context_vars (translator_output* o); }; @@ -9235,6 +9239,283 @@ struct tracepoint_derived_probe_group: public generic_dpg& args): + dw (dw), probe_name (probe_name), args (args) {} + dwflpp& dw; + const string& probe_name; + vector & args; + + void visit_target_symbol (target_symbol* e); + void visit_target_symbol_arg (target_symbol* e); + void visit_target_symbol_context (target_symbol* e); +}; + + +void +tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) +{ + string argname = e->base_name.substr(1); + + // 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) + { + arg = &args[i]; + arg->used = true; + break; + } + + if (arg == NULL) + { + stringstream alternatives; + for (unsigned i = 0; i < args.size(); ++i) + alternatives << " $" << args[i].name; + alternatives << " $$name $$vars"; + + // We hope that this value ends up not being referenced after all, so it + // can be optimized out quietly. + semantic_error* saveme = + new semantic_error("unable to find tracepoint variable '" + e->base_name + + "' (alternatives:" + alternatives.str () + ")", e->tok); + // NB: we can have multiple errors, since a target variable + // may be expanded in several different contexts: + // trace ("*") { $foo->bar } + saveme->chain = e->saved_conversion_error; + e->saved_conversion_error = saveme; + provide (e); + return; + } + + // make sure we're not dereferencing base types + if (!e->components.empty() && !arg->isptr) + switch (e->components[0].first) + { + case target_symbol::comp_literal_array_index: + throw semantic_error("tracepoint variable '" + e->base_name + + "' may not be used as array", e->tok); + case target_symbol::comp_struct_member: + throw semantic_error("tracepoint variable '" + e->base_name + + "' may not be used as a structure", e->tok); + default: + throw semantic_error("invalid use of tracepoint variable '" + + e->base_name + "'", e->tok); + } + + // we can only write to dereferenced fields, and only if guru mode is on + bool lvalue = is_active_lvalue(e); + if (lvalue && (!dw.sess.guru_mode || e->components.empty())) + throw semantic_error("write to tracepoint variable '" + e->base_name + + "' not permitted", e->tok); + + if (e->components.empty()) + { + // Synthesize a simple function to grab the parameter + functiondecl *fdecl = new functiondecl; + fdecl->tok = e->tok; + embeddedcode *ec = new embeddedcode; + ec->tok = e->tok; + + string fname = (string("_tracepoint_tvar_get") + + "_" + e->base_name.substr(1) + + "_" + lex_cast(tick++)); + + fdecl->name = fname; + fdecl->body = ec; + fdecl->type = pe_long; + + ec->code = (string("THIS->__retvalue = CONTEXT->locals[0].") + + probe_name + string(".__tracepoint_arg_") + + arg->name + string (";/* pure */")); + + dw.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 + + provide (n); + } + else + { + // Synthesize a function to dereference the dwarf fields, + // with a pointer parameter that is the base tracepoint variable + functiondecl *fdecl = new functiondecl; + fdecl->tok = e->tok; + embeddedcode *ec = new embeddedcode; + ec->tok = e->tok; + + string fname = (string(lvalue ? "_tracepoint_tvar_set" : "_tracepoint_tvar_get") + + "_" + e->base_name.substr(1) + + "_" + lex_cast(tick++)); + + fdecl->name = fname; + fdecl->body = ec; + + try + { + ec->code = dw.literal_stmt_for_pointer (&arg->type_die, e->components, + lvalue, fdecl->type); + } + catch (const semantic_error& er) + { + // We suppress this error message, and pass the unresolved + // variable 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* saveme = new semantic_error (er); // copy it + saveme->tok1 = e->tok; // XXX: token not passed to dw code generation routines + // NB: we can have multiple errors, since a target variable + // may be expanded in several different contexts: + // trace ("*") { $foo->bar } + saveme->chain = e->saved_conversion_error; + e->saved_conversion_error = saveme; + provide (e); + return; + } + + // Give the fdecl an argument for the raw tracepoint value + vardecl *v1 = new vardecl; + v1->type = pe_long; + v1->name = "pointer"; + v1->tok = e->tok; + fdecl->formal_args.push_back(v1); + + if (lvalue) + { + // Modify the fdecl so it carries a pe_long formal + // argument called "value". + + // FIXME: For the time being we only support setting target + // variables which have base types; these are 'pe_long' in + // stap's type vocabulary. Strings and pointers might be + // reasonable, some day, but not today. + + vardecl *v2 = new vardecl; + v2->type = pe_long; + v2->name = "value"; + v2->tok = e->tok; + fdecl->formal_args.push_back(v2); + } + else + ec->code += "/* pure */"; + + dw.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 + + // make the original a bare target symbol for the tracepoint value, + // which will be passed into the dwarf dereferencing code + e->components.clear(); + n->args.push_back(require(e)); + + 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); + } +} + + +void +tracepoint_var_expanding_visitor::visit_target_symbol_context (target_symbol* e) +{ + if (is_active_lvalue (e)) + throw semantic_error("write to tracepoint '" + e->base_name + "' not permitted", e->tok); + + if (!e->components.empty()) + switch (e->components[0].first) + { + case target_symbol::comp_literal_array_index: + throw semantic_error("tracepoint '" + e->base_name + "' may not be used as array", + e->tok); + case target_symbol::comp_struct_member: + throw semantic_error("tracepoint '" + e->base_name + "' may not be used as a structure", + e->tok); + default: + throw semantic_error("invalid tracepoint '" + e->base_name + "' use", e->tok); + } + + if (e->base_name == "$$name") + { + // Synthesize a functioncall. + functioncall* n = new functioncall; + n->tok = e->tok; + n->function = "_mark_name_get"; + n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session + provide (n); + } + else if (e->base_name == "$$vars") + { + target_symbol *tsym = new target_symbol; + print_format* pf = new print_format; + + // Convert $$vars to sprintf of a list of vars which we recursively evaluate + // NB: we synthesize a new token here rather than reusing + // e->tok, because print_format::print likes to use + // its tok->content. + token* pf_tok = new token(*e->tok); + pf_tok->content = "sprintf"; + + pf->tok = pf_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; + + for (unsigned i = 0; i < args.size(); ++i) + { + if (i > 0) + pf->raw_components += " "; + pf->raw_components += args[i].name; + tsym->tok = e->tok; + tsym->base_name = "$" + args[i].name; + + // every variable should always be accessible! + tsym->saved_conversion_error = 0; + expression *texp = require (tsym); // NB: throws nothing ... + assert (!tsym->saved_conversion_error); // ... but this is how we know it happened. + + pf->raw_components += "=%#x"; + pf->args.push_back(texp); + } + + pf->components = print_format::string_to_components(pf->raw_components); + provide (pf); + } + else + assert(0); // shouldn't get here +} + +void +tracepoint_var_expanding_visitor::visit_target_symbol (target_symbol* e) +{ + assert(e->base_name.size() > 0 && e->base_name[0] == '$'); + + if (e->base_name == "$$name" || e->base_name == "$$vars") + visit_target_symbol_context (e); + else + visit_target_symbol_arg (e); +} + + + tracepoint_derived_probe::tracepoint_derived_probe (systemtap_session& s, dwflpp& dw, Dwarf_Die& func_die, const string& tracepoint_name, @@ -9267,6 +9548,10 @@ tracepoint_derived_probe::tracepoint_derived_probe (systemtap_session& s, if (header_pos != string::npos) header.erase(header_pos, 12); + // Now expand the local variables in the probe body + tracepoint_var_expanding_visitor v (dw, name, args); + this->body = v.require (this->body); + if (sess.verbose > 2) clog << "tracepoint-based " << name << " tracepoint='" << tracepoint_name << "'" << endl; @@ -9326,6 +9611,36 @@ dwarf_type_name(Dwarf_Die& type_die, string& c_type) } +static bool +resolve_tracepoint_arg_type(Dwarf_Die& type_die, bool& isptr) +{ + Dwarf_Attribute type_attr; + switch (dwarf_tag(&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)); + case DW_TAG_base_type: + // base types will simply be treated as script longs + 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)); + default: + // should we consider other types too? + return false; + } +} + + void tracepoint_derived_probe::build_args(dwflpp& dw, Dwarf_Die& func_die) { @@ -9340,10 +9655,10 @@ tracepoint_derived_probe::build_args(dwflpp& dw, Dwarf_Die& func_die) // read the type of this parameter Dwarf_Attribute type_attr; - Dwarf_Die type_die; if (!dwarf_attr_integrate (&arg, DW_AT_type, &type_attr) - || !dwarf_formref_die (&type_attr, &type_die) - || !dwarf_type_name(type_die, tparg.c_type)) + || !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)) throw semantic_error ("cannot get type of tracepoint '" + tracepoint_name + "' parameter '" + tparg.name + "'"); @@ -9367,6 +9682,15 @@ tracepoint_derived_probe::join_group (systemtap_session& s) } +void +tracepoint_derived_probe::emit_probe_context_vars (translator_output* o) +{ + for (unsigned i = 0; i < args.size(); i++) + if (args[i].used) + o->newline() << "int64_t __tracepoint_arg_" << args[i].name << ";"; +} + + void tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s) { @@ -9392,6 +9716,17 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s) common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); s.op->newline() << "c->probe_point = " << lex_cast_qstring (*p->sole_location()) << ";"; + s.op->newline() << "c->marker_name = " + << lex_cast_qstring (p->tracepoint_name) << ";"; + for (unsigned j = 0; j < p->args.size(); ++j) + if (p->args[j].used) + { + 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() << "__tracepoint_arg_" << p->args[j].name << ";"; + } s.op->newline() << p->name << " (c);"; common_probe_entryfn_epilogue (s.op); s.op->newline(-1) << "}"; -- cgit From ddc5ee5a548c8c945b63d9e3076efb12272d2617 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 6 Mar 2009 19:30:39 -0800 Subject: Ensure tracepoints are synchronized after unreg The tracepoint API provides tracepoint_synchronize_unregister() as a way to guarantee that all tracepoint handlers are inactive. This is necessary after unregistering to allow the module to safely unload. * tapsets.cxx (tracepoint_derived_probe_group::emit_module_init): Call synchronize after unregistering tracepoints. (tracepoint_derived_probe_group::emit_module_exit): Ditto. --- tapsets.cxx | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 5aa67e4d..defaf385 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -9764,6 +9764,9 @@ tracepoint_derived_probe_group::emit_module_init (systemtap_session &s) << "(enter_tracepoint_probe_" << i << ");"; s.op->newline(-2) << "}"; } + s.op->newline() << "if (rc)"; + s.op->newline(1) << "tracepoint_synchronize_unregister();"; + s.op->indent(-1); } @@ -9777,6 +9780,7 @@ tracepoint_derived_probe_group::emit_module_exit (systemtap_session& s) for (unsigned i = 0; i < probes.size(); ++i) s.op->newline() << "unregister_trace_" << probes[i]->tracepoint_name << "(enter_tracepoint_probe_" << i << ");"; + s.op->newline() << "tracepoint_synchronize_unregister();"; } -- cgit From bc9a523d505c604c187dd2e81be1e24ec877d1af Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sat, 7 Mar 2009 12:11:45 -0500 Subject: Tweak tracepoint logic to run on tracepoint_synchronize_unregister()-less RHEL5 --- tapsets.cxx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index defaf385..5ea3982d 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -9764,9 +9764,15 @@ tracepoint_derived_probe_group::emit_module_init (systemtap_session &s) << "(enter_tracepoint_probe_" << i << ");"; s.op->newline(-2) << "}"; } - s.op->newline() << "if (rc)"; - s.op->newline(1) << "tracepoint_synchronize_unregister();"; - s.op->indent(-1); + + // This would be technically proper (on those autoconf-detectable + // kernels that include this function in tracepoint.h), however we + // already make several calls to synchronze_sched() during our + // shutdown processes. + + // s.op->newline() << "if (rc)"; + // s.op->newline(1) << "tracepoint_synchronize_unregister();"; + // s.op->indent(-1); } @@ -9780,7 +9786,10 @@ tracepoint_derived_probe_group::emit_module_exit (systemtap_session& s) for (unsigned i = 0; i < probes.size(); ++i) s.op->newline() << "unregister_trace_" << probes[i]->tracepoint_name << "(enter_tracepoint_probe_" << i << ");"; - s.op->newline() << "tracepoint_synchronize_unregister();"; + + // Not necessary: see above. + + // s.op->newline() << "tracepoint_synchronize_unregister();"; } -- cgit From c12d974f4ad369f8d7585f2f07713dae3654b3fb Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sat, 7 Mar 2009 17:00:54 -0500 Subject: PR9930: reentrancy debugging If stap is run with "-t -DDEBUG_REENTRANCY", additional warnings will be printed for every reentrancy event, including the probe points of the resident and interloper probes. * tapsets.cxx (common_probe_entryfn_prologue): Add "new_pp" argument, update all callers. Print reentrancy details if needed. --- tapsets.cxx | 73 +++++++++++++++++++++++++++++-------------------------------- 1 file changed, 35 insertions(+), 38 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 5ea3982d..02f0b553 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -158,6 +158,7 @@ be_derived_probe::join_group (systemtap_session& s) // ------------------------------------------------------------------------ void common_probe_entryfn_prologue (translator_output* o, string statestr, + string new_pp, bool overload_processing = true, bool interruptible = true) { @@ -207,6 +208,15 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, o->newline(1) << "atomic_inc (& skipped_count);"; o->newline() << "#ifdef STP_TIMING"; o->newline() << "atomic_inc (& skipped_count_reentrant);"; + o->newline() << "#ifdef DEBUG_REENTRANCY"; + o->newline() << "_stp_warn (\"Skipped %s due to %s residency on cpu %u\\n\", " + << new_pp << ", c->probe_point ?: \"?\", smp_processor_id());"; + // NB: There is a conceivable race condition here with reading + // c->probe_point, knowing that this other probe is sort of running. + // However, in reality, it's interrupted. Plus even if it were able + // to somehow start again, and stop before we read c->probe_point, + // at least we have that ?: "?" bit in there to avoid a NULL deref. + o->newline() << "#endif"; o->newline() << "#endif"; o->newline() << "atomic_dec (& c->busy);"; o->newline() << "goto probe_epilogue;"; @@ -217,12 +227,12 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, o->newline() << "c->nesting = 0;"; o->newline() << "c->regs = 0;"; o->newline() << "c->unwaddr = 0;"; + o->newline() << "c->probe_point = " << new_pp << ";"; // reset unwound address cache o->newline() << "c->pi = 0;"; o->newline() << "c->regparm = 0;"; o->newline() << "c->marker_name = NULL;"; o->newline() << "c->marker_format = NULL;"; - o->newline() << "c->probe_point = 0;"; if (! interruptible) o->newline() << "c->actionremaining = MAXACTION;"; else @@ -290,6 +300,7 @@ common_probe_entryfn_epilogue (translator_output* o, o->newline() << "c->cycles_base = cycles_atend;"; o->newline() << "c->cycles_sum = 0;"; + o->newline() << "c->probe_point = 0;"; // vacated o->newline(-1) << "}"; o->newline(-1) << "}"; o->newline() << "#endif"; @@ -338,24 +349,21 @@ be_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "/* ---- begin/end probes ---- */"; s.op->newline() << "static void enter_begin_probe (void (*fn)(struct context*), const char* pp) {"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_STARTING", false, true); - s.op->newline() << "c->probe_point = pp;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_STARTING", "pp", false, true); s.op->newline() << "(*fn) (c);"; common_probe_entryfn_epilogue (s.op, false, true); s.op->newline(-1) << "}"; s.op->newline() << "static void enter_end_probe (void (*fn)(struct context*), const char* pp) {"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_STOPPING", false, true); - s.op->newline() << "c->probe_point = pp;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_STOPPING", "pp", false, true); s.op->newline() << "(*fn) (c);"; common_probe_entryfn_epilogue (s.op, false, true); s.op->newline(-1) << "}"; s.op->newline() << "static void enter_error_probe (void (*fn)(struct context*), const char* pp) {"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_ERROR", false, true); - s.op->newline() << "c->probe_point = pp;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_ERROR", "pp", false, true); s.op->newline() << "(*fn) (c);"; common_probe_entryfn_epilogue (s.op, false, true); s.op->newline(-1) << "}"; @@ -5467,8 +5475,7 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->line() << "kprobe_idx:0)"; // NB: at least we avoid memory corruption // XXX: it would be nice to give a more verbose error though; BUG_ON later? s.op->line() << "];"; - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); - s.op->newline() << "c->probe_point = sdp->pp;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->pp"); s.op->newline() << "c->regs = regs;"; s.op->newline() << "(*sdp->ph) (c);"; common_probe_entryfn_epilogue (s.op); @@ -5490,8 +5497,7 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) // XXX: it would be nice to give a more verbose error though; BUG_ON later? s.op->line() << "];"; - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); - s.op->newline() << "c->probe_point = sdp->pp;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->pp"); s.op->newline() << "c->regs = regs;"; s.op->newline() << "c->pi = inst;"; // for assisting runtime's backtrace logic s.op->newline() << "(*sdp->ph) (c);"; @@ -6381,8 +6387,7 @@ itrace_derived_probe_group::emit_module_decls (systemtap_session& s) 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;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp"); s.op->newline() << "c->regs = regs;"; s.op->newline() << "c->data = data;"; @@ -6974,8 +6979,7 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "static void stap_utrace_probe_handler(struct task_struct *tsk, struct stap_utrace_probe *p) {"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); - s.op->newline() << "c->probe_point = p->pp;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp"); // call probe function s.op->newline() << "(*p->ph) (c);"; @@ -6997,8 +7001,7 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->indent(1); s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;"; - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); - s.op->newline() << "c->probe_point = p->pp;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp"); s.op->newline() << "c->regs = regs;"; // call probe function @@ -7486,10 +7489,9 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "static void enter_uprobe_probe (struct uprobe *inst, struct pt_regs *regs) {"; s.op->newline(1) << "struct stap_uprobe *sup = container_of(inst, struct stap_uprobe, up);"; s.op->newline() << "struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];"; - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sups->pp"); s.op->newline() << "if (sup->spec_index < 0 ||" << "sup->spec_index >= " << probes.size() << ") return;"; // XXX: should not happen - s.op->newline() << "c->probe_point = sups->pp;"; s.op->newline() << "c->regs = regs;"; s.op->newline() << "(*sups->ph) (c);"; common_probe_entryfn_epilogue (s.op); @@ -7498,10 +7500,9 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "static void enter_uretprobe_probe (struct uretprobe_instance *inst, struct pt_regs *regs) {"; s.op->newline(1) << "struct stap_uprobe *sup = container_of(inst->rp, struct stap_uprobe, urp);"; s.op->newline() << "struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];"; - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sups->pp"); s.op->newline() << "if (sup->spec_index < 0 ||" << "sup->spec_index >= " << probes.size() << ") return;"; // XXX: should not happen - s.op->newline() << "c->probe_point = sups->pp;"; // XXX: kretprobes saves "c->pi = inst;" too s.op->newline() << "c->regs = regs;"; s.op->newline() << "(*sups->ph) (c);"; @@ -7828,8 +7829,7 @@ timer_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->line() << ");"; s.op->newline(-1) << "{"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); - s.op->newline() << "c->probe_point = stp->pp;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->pp"); s.op->newline() << "(*stp->ph) (c);"; common_probe_entryfn_epilogue (s.op); s.op->newline(-1) << "}"; @@ -7951,8 +7951,8 @@ profile_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "static void enter_all_profile_probes (struct pt_regs *regs) {"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); - s.op->newline() << "c->probe_point = \"timer.profile\";"; // NB: hard-coded for convenience + string pp = lex_cast_qstring("timer.profile"); // hard-coded for convenience + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", pp); s.op->newline() << "c->regs = regs;"; for (unsigned i=0; inewline() << "int bytes = 0;"; s.op->newline() << "string_t strdata = {'\\0'};"; - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); - s.op->newline() << "c->probe_point = spp->read_pp;"; + 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;"; @@ -8251,8 +8250,7 @@ procfs_derived_probe_group::emit_module_decls (systemtap_session& s) 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"); - s.op->newline() << "c->probe_point = spp->write_pp;"; + 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;"; @@ -9012,8 +9010,7 @@ mark_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(); s.op->newline() << "static void enter_marker_probe (void *probe_data, void *call_data, const char *fmt, va_list *args) {"; s.op->newline(1) << "struct stap_marker_probe *smp = (struct stap_marker_probe *)probe_data;"; - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); - s.op->newline() << "c->probe_point = smp->pp;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "smp->pp"); s.op->newline() << "c->marker_name = smp->name;"; s.op->newline() << "c->marker_format = smp->format;"; s.op->newline() << "c->mark_va_list = args;"; @@ -9713,11 +9710,11 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s) } s.op->line() << ") {"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); - s.op->newline() << "c->probe_point = " - << lex_cast_qstring (*p->sole_location()) << ";"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", + lex_cast_qstring (*p->sole_location())); s.op->newline() << "c->marker_name = " - << lex_cast_qstring (p->tracepoint_name) << ";"; + << lex_cast_qstring (p->tracepoint_name) + << ";"; for (unsigned j = 0; j < p->args.size(); ++j) if (p->args[j].used) { @@ -10070,8 +10067,7 @@ hrtimer_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(-1) << "}"; s.op->newline() << "{"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING"); - s.op->newline() << "c->probe_point = stp->pp;"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->pp"); s.op->newline() << "(*stp->ph) (c);"; common_probe_entryfn_epilogue (s.op); s.op->newline(-1) << "}"; @@ -10435,7 +10431,8 @@ perfmon_derived_probe::emit_probe_entries (translator_output * o) emit_probe_prologue (o, (mode == perfmon_count ? "STAP_SESSION_STARTING" : - "STAP_SESSION_RUNNING")); + "STAP_SESSION_RUNNING"), + "probe_point"); // NB: locals are initialized by probe function itself o->newline() << name << " (c);"; -- cgit From 9b692b91ee25c33281c32c7ba86f5f0734e46be9 Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Sun, 8 Mar 2009 19:55:05 -0400 Subject: Fix and add tests for function(".so").statement(N) * tapsets.cxx (query_dwarf_func): die_has_pc (dwarf_haspc) does not expect a module_start for shared objects so don't call module_address_to_global for the statement address. * testsuite/systemtap.base/labels.exp: Add tests for executable .statement(N), shared object .label("L") and so .statement(N). --- tapsets.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 02f0b553..d99eebe2 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3920,9 +3920,9 @@ query_dwarf_func (Dwarf_Die * func, base_query * bq) else if (q->has_function_num || q->has_statement_num) { Dwarf_Addr query_addr = - q->dw.module_address_to_global(q->has_function_num ? q->function_num_val : - q->has_statement_num ? q->statement_num_val : - (assert(0) , 0)); + (q->has_function_num ? q->function_num_val : + q->has_statement_num ? q->statement_num_val : + (assert(0) , 0)); Dwarf_Die d; q->dw.function_die (&d); -- cgit From c3add01f692e698995a62c13e154bab35d9212df Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 9 Mar 2009 17:23:05 -0700 Subject: Update location of c->probe_point reset The probe_point clear was nested in the overload processing code, I believe accidentally. This just makes it always cleared on probe exit. --- tapsets.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index d99eebe2..18bd75f5 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -300,7 +300,6 @@ common_probe_entryfn_epilogue (translator_output* o, o->newline() << "c->cycles_base = cycles_atend;"; o->newline() << "c->cycles_sum = 0;"; - o->newline() << "c->probe_point = 0;"; // vacated o->newline(-1) << "}"; o->newline(-1) << "}"; o->newline() << "#endif"; @@ -309,6 +308,7 @@ common_probe_entryfn_epilogue (translator_output* o, o->newline(-1) << "}"; o->newline() << "#endif"; + o->newline() << "c->probe_point = 0;"; // vacated o->newline() << "if (unlikely (c->last_error && c->last_error[0])) {"; o->newline(1) << "if (c->last_stmt != NULL)"; o->newline(1) << "_stp_softerror (\"%s near %s\", c->last_error, c->last_stmt);"; -- cgit From 046e719028ae6b037fb7342b7d0764985bfaf408 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 9 Mar 2009 17:37:14 -0700 Subject: Add tracepoint $$parms alias for $$vars For parity with the DWARF probes, this makes tracepoints also define $$parms, which has the same value as $$vars (since tracepoints are missing the concept of $$locals). --- tapsets.cxx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 18bd75f5..b748a487 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -9271,7 +9271,7 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) stringstream alternatives; for (unsigned i = 0; i < args.size(); ++i) alternatives << " $" << args[i].name; - alternatives << " $$name $$vars"; + alternatives << " $$name $$parms $$vars"; // We hope that this value ends up not being referenced after all, so it // can be optimized out quietly. @@ -9457,7 +9457,7 @@ tracepoint_var_expanding_visitor::visit_target_symbol_context (target_symbol* e) n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session provide (n); } - else if (e->base_name == "$$vars") + else if (e->base_name == "$$vars" || e->base_name == "$$parms") { target_symbol *tsym = new target_symbol; print_format* pf = new print_format; @@ -9505,7 +9505,9 @@ tracepoint_var_expanding_visitor::visit_target_symbol (target_symbol* e) { assert(e->base_name.size() > 0 && e->base_name[0] == '$'); - if (e->base_name == "$$name" || e->base_name == "$$vars") + if (e->base_name == "$$name" || + e->base_name == "$$parms" || + e->base_name == "$$vars") visit_target_symbol_context (e); else visit_target_symbol_arg (e); -- cgit From e0a17418b9d12e2a95dc345e95080ba31a41677f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 9 Mar 2009 19:12:02 -0700 Subject: Let -DINTERRUPTIBLE=0 mask interrupts in probes Some time ago we loosened up the code for all probe types to allow interrupts during the handler. However, when probing something like kernel.trace("*"), you get a mix of probes in and out of the interrupt path, and it becomes much more common to have probes skipped due to interrupt reentrancy. The common_probe_entryfn_prologue and common_probe_entryfn_epilogue functions had an interruptible flag, but this was no longer used anywhere. I removed this flag, but then reused the logic to check an INTERRUPTIBLE macro instead. Now users can use -DINTERRUPTIBLE=0 to prevent interrupt reentrancy in their script, at the cost of a bit more overhead to toggle the interrupt mask. --- tapsets.cxx | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index b748a487..ce9a0ca1 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -159,12 +159,12 @@ be_derived_probe::join_group (systemtap_session& s) void common_probe_entryfn_prologue (translator_output* o, string statestr, string new_pp, - bool overload_processing = true, - bool interruptible = true) + bool overload_processing = true) { o->newline() << "struct context* __restrict__ c;"; - if (! interruptible) - o->newline() << "unsigned long flags;"; + o->newline() << "#if !INTERRUPTIBLE"; + o->newline() << "unsigned long flags;"; + o->newline() << "#endif"; if (overload_processing) o->newline() << "#if defined(STP_TIMING) || defined(STP_OVERLOAD)"; @@ -182,10 +182,11 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, o->newline() << "static int _pfm_num_pmd_x;"; #endif - if (! interruptible) - o->newline() << "local_irq_save (flags);"; - else - o->newline() << "preempt_disable ();"; + o->newline() << "#if INTERRUPTIBLE"; + o->newline() << "preempt_disable ();"; + o->newline() << "#else"; + o->newline() << "local_irq_save (flags);"; + o->newline() << "#endif"; // Check for enough free enough stack space o->newline() << "if (unlikely ((((unsigned long) (& c)) & (THREAD_SIZE-1))"; // free space @@ -233,10 +234,12 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, o->newline() << "c->regparm = 0;"; o->newline() << "c->marker_name = NULL;"; o->newline() << "c->marker_format = NULL;"; - if (! interruptible) - o->newline() << "c->actionremaining = MAXACTION;"; - else - o->newline() << "c->actionremaining = MAXACTION_INTERRUPTIBLE;"; + + o->newline() << "#if INTERRUPTIBLE"; + o->newline() << "c->actionremaining = MAXACTION_INTERRUPTIBLE;"; + o->newline() << "#else"; + o->newline() << "c->actionremaining = MAXACTION;"; + o->newline() << "#endif"; o->newline() << "#ifdef STP_TIMING"; o->newline() << "c->statp = 0;"; o->newline() << "#endif"; @@ -255,8 +258,7 @@ common_probe_entryfn_prologue (translator_output* o, string statestr, void common_probe_entryfn_epilogue (translator_output* o, - bool overload_processing = true, - bool interruptible = true) + bool overload_processing = true) { if (overload_processing) o->newline() << "#if defined(STP_TIMING) || defined(STP_OVERLOAD)"; @@ -332,10 +334,11 @@ common_probe_entryfn_epilogue (translator_output* o, o->newline() << "_stp_exit ();"; o->newline(-1) << "}"; - if (! interruptible) - o->newline() << "local_irq_restore (flags);"; - else - o->newline() << "preempt_enable_no_resched ();"; + o->newline() << "#if INTERRUPTIBLE"; + o->newline() << "preempt_enable_no_resched ();"; + o->newline() << "#else"; + o->newline() << "local_irq_restore (flags);"; + o->newline() << "#endif"; } @@ -349,23 +352,23 @@ be_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "/* ---- begin/end probes ---- */"; s.op->newline() << "static void enter_begin_probe (void (*fn)(struct context*), const char* pp) {"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_STARTING", "pp", false, true); + common_probe_entryfn_prologue (s.op, "STAP_SESSION_STARTING", "pp", false); s.op->newline() << "(*fn) (c);"; - common_probe_entryfn_epilogue (s.op, false, true); + common_probe_entryfn_epilogue (s.op, false); s.op->newline(-1) << "}"; s.op->newline() << "static void enter_end_probe (void (*fn)(struct context*), const char* pp) {"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_STOPPING", "pp", false, true); + common_probe_entryfn_prologue (s.op, "STAP_SESSION_STOPPING", "pp", false); s.op->newline() << "(*fn) (c);"; - common_probe_entryfn_epilogue (s.op, false, true); + common_probe_entryfn_epilogue (s.op, false); s.op->newline(-1) << "}"; s.op->newline() << "static void enter_error_probe (void (*fn)(struct context*), const char* pp) {"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_ERROR", "pp", false, true); + common_probe_entryfn_prologue (s.op, "STAP_SESSION_ERROR", "pp", false); s.op->newline() << "(*fn) (c);"; - common_probe_entryfn_epilogue (s.op, false, true); + common_probe_entryfn_epilogue (s.op, false); s.op->newline(-1) << "}"; s.op->newline() << "static struct stap_be_probe {"; -- cgit From abb41d920aecf908a132597f0a4bc26a10e58a7c Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 10 Mar 2009 15:32:16 -0700 Subject: PR9932: add @cast module search path Sometimes @cast()ing can fail if the type needed may or may not be defined in a kernel module. This patch lets @cast take a colon- separated list of modules to search for the type definition. * tapsets.cxx (dwarf_cast_query): Simplify. Take the module and the code result as reference parameters, and use code.empty() as the sign that the type isn't resolved yet. (dwarf_cast_expanding_visitor::visit_cast_op): Split e->module by colon into substrings, and loop until the type is resolved. --- tapsets.cxx | 69 +++++++++++++++++++++++++++---------------------------------- 1 file changed, 30 insertions(+), 39 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index ce9a0ca1..b66dd123 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -4913,14 +4913,14 @@ struct dwarf_cast_query : public base_query { const cast_op& e; const bool lvalue; - exp_type& pe_type; - bool resolved; - string code; + exp_type& pe_type; + string& code; - dwarf_cast_query(dwflpp& dw, const cast_op& e, bool lvalue, exp_type& pe_type): - base_query(dw, e.module), e(e), lvalue(lvalue), pe_type(pe_type), resolved(false) {} - const string& get_code(); + dwarf_cast_query(dwflpp& dw, const string& module, const cast_op& e, + bool lvalue, exp_type& pe_type, string& code): + base_query(dw, module), e(e), lvalue(lvalue), + pe_type(pe_type), code(code) {} void handle_query_module(); int handle_query_cu(Dwarf_Die * cudie); @@ -4929,23 +4929,10 @@ struct dwarf_cast_query : public base_query }; -const string& -dwarf_cast_query::get_code() -{ - if (!resolved) - dw.query_modules(this); - - if (!resolved) - throw semantic_error("type definition not found"); - - return code; -} - - void dwarf_cast_query::handle_query_module() { - if (resolved) + if (!code.empty()) return; // look for the type in each CU @@ -4956,7 +4943,7 @@ dwarf_cast_query::handle_query_module() int dwarf_cast_query::handle_query_cu(Dwarf_Die * cudie) { - if (resolved) + if (!code.empty()) return DWARF_CB_ABORT; dw.focus_on_cu (cudie); @@ -4973,10 +4960,7 @@ dwarf_cast_query::handle_query_cu(Dwarf_Die * cudie) // XXX might be better to save the error // and try again in another CU sess.print_error (e); - return DWARF_CB_ABORT; } - - resolved = true; return DWARF_CB_ABORT; } return DWARF_CB_OK; @@ -5014,12 +4998,18 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) string code; exp_type type = pe_long; - try + size_t mod_end = -1; + do { + // 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); + // NB: This uses '/' to distinguish between kernel modules and userspace, // which means that userspace modules won't get any PATH searching. dwflpp* dw; - if (e->module.find('/') == string::npos) + if (module.find('/') == string::npos) { // kernel or kernel module target if (! db.kern_dw) @@ -5031,36 +5021,37 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) } else { - e->module = find_executable (e->module); // canonicalize it + module = find_executable (module); // canonicalize it // user-space target; we use one dwflpp instance per module name // (= program or shared library) - if (db.user_dw.find(e->module) == db.user_dw.end()) + if (db.user_dw.find(module) == db.user_dw.end()) { dw = new dwflpp(s); - dw->setup_user(e->module); - db.user_dw[e->module] = dw; + dw->setup_user(module); + db.user_dw[module] = dw; } else - dw = db.user_dw[e->module]; + dw = db.user_dw[module]; } - dwarf_cast_query q (*dw, *e, lvalue, type); - code = q.get_code(); + dwarf_cast_query q (*dw, module, *e, lvalue, type, code); + dw->query_modules(&q); } - catch (const semantic_error& er) + while (code.empty() && mod_end != string::npos); + + if (code.empty()) { - // We suppress this error message, and pass the unresolved + // We generate an error message, and pass the unresolved // 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* saveme = new semantic_error (er); // copy it - saveme->tok1 = e->tok; // XXX: token not passed to dw code generation routines + semantic_error* er = new semantic_error ("type definition not found", e->tok); // NB: we can have multiple errors, since a @cast // may be expanded in several different contexts: // function ("*") { @cast(...) } - saveme->chain = e->saved_conversion_error; - e->saved_conversion_error = saveme; + er->chain = e->saved_conversion_error; + e->saved_conversion_error = er; provide (e); return; } -- cgit From e2086848b3b1e010249f68857ec10d6b9382446e Mon Sep 17 00:00:00 2001 From: Wenji Huang Date: Mon, 9 Mar 2009 08:17:27 -0400 Subject: Make tracepoint probe support listing mode -L This patch is to enable displaying arguments of tracepoint probe in listing mode -L. The example output is like $stap -L 'kernel.trace("block_bio*")' kernel.trace("block_bio_bounce") $q:struct request_queue* $bio:struct bio* kernel.trace("block_bio_backmerge") $q:struct request_queue* $bio:struct bio* kernel.trace("block_bio_complete") $q:struct request_queue* $bio:struct bio* kernel.trace("block_bio_queue") $q:struct request_queue* $bio:struct bio* kernel.trace("block_bio_frontmerge") $q:struct request_queue* $bio:struct bio* Signed-off-by: Wenji Huang --- tapsets.cxx | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index b66dd123..71a9a768 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -9217,6 +9217,7 @@ struct tracepoint_derived_probe: public derived_probe vector args; void build_args(dwflpp& dw, Dwarf_Die& func_die); + void printargs (std::ostream &o) const; void join_group (systemtap_session& s); void emit_probe_context_vars (translator_output* o); }; @@ -9665,6 +9666,12 @@ tracepoint_derived_probe::build_args(dwflpp& dw, Dwarf_Die& func_die) while (dwarf_siblingof(&arg, &arg) == 0); } +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; +} void tracepoint_derived_probe::join_group (systemtap_session& s) -- cgit From 89f3a1254ccf16a6828671c6e5bc407bc061f040 Mon Sep 17 00:00:00 2001 From: Wenji Huang Date: Mon, 9 Mar 2009 10:05:42 -0400 Subject: Make marker probe support listing mode -L This patch is to enable displaying the arguments of marker probe for listing mode -L. The output is like, $stap -L 'kernel.mark("*")' kernel.mark("core_marker_format").format("name %s format %s") $arg1:string $arg2:string kernel.mark("jbd2_checkpoint").format("dev %s need_checkpoint %d") $arg1:string $arg2:long kernel.mark("jbd2_end_commit").format("dev %s transaction %d head %d") $arg1:string $arg2:long $arg3:long kernel.mark("jbd2_start_commit").format("dev %s transaction %d") $arg1:string $arg2:long Note: It's also possible to figure out the arguments according to the format. Signed-off-by: Wenji Huang --- tapsets.cxx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 71a9a768..b1d0b04e 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -8523,6 +8523,7 @@ struct mark_derived_probe: public derived_probe void join_group (systemtap_session& s); void emit_probe_context_vars (translator_output* o); void initialize_probe_context_vars (translator_output* o); + void printargs (std::ostream &o) const; void parse_probe_format (); }; @@ -8967,6 +8968,27 @@ mark_derived_probe::initialize_probe_context_vars (translator_output* o) o->newline() << "deref_fault: ;"; } +void +mark_derived_probe::printargs(std::ostream &o) const +{ + for (unsigned i = 0; i < mark_args.size(); i++) + { + string localname = "$arg" + lex_cast(i+1); + switch (mark_args[i]->stp_type) + { + case pe_long: + o << " " << localname << ":long"; + break; + case pe_string: + o << " " << localname << ":string"; + break; + default: + o << " " << localname << ":unknown"; + break; + } + } +} + void mark_derived_probe_group::emit_module_decls (systemtap_session& s) -- cgit From 3bd0d4df7ccfd9afe7771441b26d8baaaf180e29 Mon Sep 17 00:00:00 2001 From: Rajan Arora Date: Wed, 11 Mar 2009 18:44:21 -0400 Subject: PR 7071: Optional $context variables fix * tapsets.cxx (dwarf_var_expanding_visitor::visit_target_symbol): Substitute erroneous target symbol with literal 0 if session level flag, skip_badvars is set. * session.h (struct systemtap_session): New flag: skip_badvars. * main.cxx: Command line argument --skip-badvars added. * stap.1.in: Entry for new option --skip-badvars. * NEWS: Added blurb for new option now available. * testsuite/semok/badvar.stp: Test case to check added functionality. --- tapsets.cxx | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index b1d0b04e..dce73534 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -4842,18 +4842,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; -- cgit From 139dee87b8824df4d7562a980e886a6e6f0b8308 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 11 Mar 2009 20:07:22 -0700 Subject: Fix @cast module splitting The new semok testcase exposed that the module splitting wasn't properly setting substr boundaries. Instead of passing the end position, it's supposed to pass the number of characters (end - begin). Oops. --- tapsets.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index dce73534..7f6ca721 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -5017,7 +5017,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. -- cgit From 96b030fe8a0bb0297d23638e2975a3e9eb2b85b6 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 12 Mar 2009 10:11:59 -0700 Subject: Simplify tracepoint registrations Instead of registering tracepoints with the deeply-nested if-tree, which was cluttering the module_init/exit, this now emits normalized reg/unreg functions for each tracepoint probes. Now the module_init/exit can be a simple loop like all of the other probe types. --- tapsets.cxx | 71 +++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 28 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 7f6ca721..b02e2cce 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -9732,12 +9732,15 @@ 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 << "("; for (unsigned j = 0; j < p->args.size(); ++j) @@ -9765,8 +9768,34 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s) 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) << "}"; + s.op->newline() << "static int unregister_tracepoint_probe_" << i << "(void) {"; + s.op->newline(1) << "return 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) << "int (*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=®ister_tracepoint_probe_" << i << ","; + s.op->line() << " .unreg=&unregister_tracepoint_probe_" << i; + s.op->line() << " },"; + } + s.op->newline(-1) << "};"; + s.op->newline(); } @@ -9777,28 +9806,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 @@ -9817,10 +9832,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. -- cgit From bb64f40b58a64a9ae065dba5058463ac604c3896 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Sun, 15 Mar 2009 15:29:01 +0100 Subject: Move vma module tracking from pr6866 branch to master. * tapsets.cxx (utrace_derived_probe_group::emit_module_decls): Always emit vm callback probe for __stp_tf_vm_cb. * runtime/task_finder.c (__stp_tf_vm_cb): Always expose, move _stp_dbug statements under ifdef DEBUG_TASK_FINDER_VMA. Find and record corresponding module when vm_path not NULL. * runtime/task_finder_vma.c (struct __stp_tf_vma_entry): Add _stp_module. (stap_add_vma_map_info): Add _stp_module argument and assign. (__stp_tf_get_vma_entry_addr): New static function to get the __stp_tf_vma_entry given an address. --- tapsets.cxx | 4 ---- 1 file changed, 4 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index b02e2cce..6efcb3af 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -7172,10 +7172,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++) { @@ -7193,10 +7191,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++) { -- cgit From 86758d5f2b838d5769c7ace15269a4ebc422f94a Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 16 Mar 2009 18:13:07 -0700 Subject: Fix regression in tracepoint unregistration Commit 96b030fe reorganized the tracepoint registration calls by creating generic wrappers that return int. However, the older tracepoint implementation (as found in RHEL5.3) returned void for unreg, so this was failing pass-4. Since we can't handle unregistration failures anyway, this change just makes the generic unregister function return void instead. As noted in the newly-added comment, it should be safe for us to ignore unreg failures. --- tapsets.cxx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 6efcb3af..2f940b29 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -9770,8 +9770,13 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(1) << "return register_trace_" << p->tracepoint_name << "(enter_tracepoint_probe_" << i << ");"; s.op->newline(-1) << "}"; - s.op->newline() << "static int unregister_tracepoint_probe_" << i << "(void) {"; - s.op->newline(1) << "return unregister_trace_" << p->tracepoint_name + + // 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(); @@ -9780,7 +9785,7 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s) // 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) << "int (*unreg)(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) -- cgit