From 7a24d42223ae98598c99bfb21437a00f13397d6d Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 22 Jul 2008 16:14:02 -0400 Subject: PR4225: parse process("path").function/statement probe points --- tapsets.cxx | 282 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 184 insertions(+), 98 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 8c2bafb1..dc7a2b9e 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -913,7 +913,7 @@ struct dwflpp return 0; } - void setup(bool kernel, bool debuginfo_needed = true) + void setup_kernel(bool debuginfo_needed = true) { if (! sess.module_cache) sess.module_cache = new module_cache (); @@ -927,14 +927,6 @@ struct dwflpp static const char *debug_path = (debuginfo_env_arr ? debuginfo_env_arr : sess.kernel_release.c_str()); - static const Dwfl_Callbacks proc_callbacks = - { - dwfl_linux_proc_find_elf, - dwfl_standard_find_debuginfo, - NULL, - & debuginfo_path - }; - static const Dwfl_Callbacks kernel_callbacks = { dwfl_linux_kernel_find_elf, @@ -943,65 +935,108 @@ struct dwflpp & debuginfo_path }; - if (kernel) + dwfl = dwfl_begin (&kernel_callbacks); + if (!dwfl) + throw semantic_error ("cannot open dwfl"); + dwfl_report_begin (dwfl); + + int (*callback)(const char *name, const char *path); + if (sess.consult_symtab && !sess.module_cache->paths_collected) { - dwfl = dwfl_begin (&kernel_callbacks); - if (!dwfl) - throw semantic_error ("cannot open dwfl"); - dwfl_report_begin (dwfl); - - int (*callback)(const char *name, const char *path); - if (sess.consult_symtab && !sess.module_cache->paths_collected) - { - callback = pathname_caching_callback; - sess.module_cache->paths_collected = true; - } - else - callback = NULL; - - // XXX: we should not need to set this static variable just - // for the callback. The following elfutils routine should - // take some void* parameter to pass context to the callback. - this_session = & sess; - int rc = dwfl_linux_kernel_report_offline (dwfl, - debug_path, - /* selection predicate */ - callback); - this_session = 0; - - if (debuginfo_needed) - dwfl_assert (string("missing kernel ") + - sess.kernel_release + - string(" ") + - sess.architecture + - string(" debuginfo"), - rc); - - // XXX: it would be nice if we could do a single - // ..._report_offline call for an entire systemtap script, so - // that a selection predicate would filter out modules outside - // the union of all the requested wildcards. But we build - // derived_probes one-by-one and we don't have lookahead. - - // XXX: a special case: if we have only kernel.* probe points, - // we shouldn't waste time looking for module debug-info (and - // vice versa). - - // NB: the result of an _offline call is the assignment of - // virtualized addresses to relocatable objects such as - // modules. These have to be converted to real addresses at - // run time. See the dwarf_derived_probe ctor and its caller. + callback = pathname_caching_callback; + sess.module_cache->paths_collected = true; } else + callback = NULL; + + // XXX: we should not need to set this static variable just + // for the callback. The following elfutils routine should + // take some void* parameter to pass context to the callback. + this_session = & sess; + int rc = dwfl_linux_kernel_report_offline (dwfl, + debug_path, + /* selection predicate */ + callback); + this_session = 0; + + if (debuginfo_needed) + dwfl_assert (string("missing kernel ") + + sess.kernel_release + + string(" ") + + sess.architecture + + string(" debuginfo"), + rc); + + // XXX: it would be nice if we could do a single + // ..._report_offline call for an entire systemtap script, so + // that a selection predicate would filter out modules outside + // the union of all the requested wildcards. But we build + // derived_probes one-by-one and we don't have lookahead. + // PR 3498. + + // XXX: a special case: if we have only kernel.* probe points, + // we shouldn't waste time looking for module debug-info (and + // vice versa). + + // NB: the result of an _offline call is the assignment of + // virtualized addresses to relocatable objects such as + // modules. These have to be converted to real addresses at + // run time. See the dwarf_derived_probe ctor and its caller. + + dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL)); + } + + void setup_user(string module_name, bool debuginfo_needed = true) + { + // XXX: this is where the session -R parameter could come in + static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug:build"; + static char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); + static char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr); + + static const Dwfl_Callbacks user_callbacks = { - dwfl = dwfl_begin (&proc_callbacks); - dwfl_report_begin (dwfl); - if (!dwfl) - throw semantic_error ("cannot open dwfl"); + NULL, /* dwfl_linux_kernel_find_elf, */ + dwfl_standard_find_debuginfo, + dwfl_offline_section_address, + & debuginfo_path + }; - throw semantic_error ("user-space probes not yet implemented"); - // XXX: Find pids or processes, do userspace stuff. - } + dwfl = dwfl_begin (&user_callbacks); + if (!dwfl) + throw semantic_error ("cannot open dwfl"); + dwfl_report_begin (dwfl); + + // XXX: pathname caching? + + // XXX: need to map module_name to fully-qualified directory names, + // searching PATH etc. + + // XXX: should support buildid-based naming + + // XXX: we should not need to set this static variable just + // for the callback. The following elfutils routine should + // take some void* parameter to pass context to the callback. + this_session = & sess; + Dwfl_Module *mod = dwfl_report_offline (dwfl, + module_name.c_str(), + module_name.c_str(), + -1); + // XXX: save mod! + + this_session = 0; + + if (debuginfo_needed) + dwfl_assert (string("missing process ") + + module_name + + string(" ") + + sess.architecture + + string(" debuginfo"), + mod); + + // NB: the result of an _offline call is the assignment of + // virtualized addresses to relocatable objects such as + // modules. These have to be converted to real addresses at + // run time. See the dwarf_derived_probe ctor and its caller. dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL)); } @@ -2405,9 +2440,11 @@ base_query::base_query(systemtap_session & sess, module_val = "kernel"; else { - bool has_module = get_string_param(params, TOK_MODULE, module_val); - assert (has_module); // no other options are possible by construction - (void) has_module; + bool has_module_or_process = + get_string_param(params, TOK_MODULE, module_val) || + get_string_param(params, TOK_PROCESS, module_val); + assert (has_module_or_process); // no other options are possible by construction + (void) has_module_or_process; // for -DNDEBUG } } @@ -2689,23 +2726,40 @@ dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, void * arg), struct dwarf_builder: public derived_probe_builder { dwflpp *kern_dw; + map user_dw; dwarf_builder(): kern_dw(0) {} - void build_no_more (systemtap_session &s) + + /* NB: not virtual, so can be called from dtor too: */ + void dwarf_build_no_more (bool verbose) { if (kern_dw) { - if (s.verbose > 3) - clog << "dwarf_builder releasing dwflpp" << endl; + if (verbose) + clog << "dwarf_builder releasing kernel dwflpp" << endl; delete kern_dw; kern_dw = 0; } + + for (map::iterator udi = user_dw.begin(); + udi != user_dw.end(); + udi ++) + { + if (verbose) + clog << "dwarf_builder releasing user dwflpp " << udi->first << endl; + delete udi->second; + } + user_dw.erase (user_dw.begin(), user_dw.end()); + } + + void build_no_more (systemtap_session &s) + { + dwarf_build_no_more (s.verbose > 3); } ~dwarf_builder() { - // XXX: in practice, NOTREACHED - delete kern_dw; + dwarf_build_no_more (false); } virtual void build(systemtap_session & sess, @@ -4527,7 +4581,7 @@ dwarf_derived_probe::register_patterns(match_node * root) register_function_and_statement_variants(root->bind_str(TOK_MODULE), dw); root->bind(TOK_KERNEL)->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)->bind(dw); - // register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw); + register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw); } void @@ -4861,39 +4915,72 @@ dwarf_builder::build(systemtap_session & sess, // XXX: but they should be per-session, as this builder object // may be reused if we try to cross-instrument multiple targets. - if (!kern_dw) + 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)) { - kern_dw = new dwflpp(sess); - assert(kern_dw); - kern_dw->setup(true); + // kernel or kernel module target + if (! kern_dw) + { + kern_dw = new dwflpp(sess); + // XXX: PR 3498 + kern_dw->setup_kernel(); + } + dw = kern_dw; + + // Extract some kernel-side blacklist/relocation information. + // XXX: This really should be per-module rather than per-kernel, since + // .ko's may conceivably contain __kprobe-marked code + Dwfl_Module* km = 0; + kern_dw->iterate_over_modules(&query_kernel_module, &km); + if (km) + { + if (! sess.sym_kprobes_text_start) + sess.sym_kprobes_text_start = lookup_symbol_address (km, "__kprobes_text_start"); + if (! sess.sym_kprobes_text_end) + sess.sym_kprobes_text_end = lookup_symbol_address (km, "__kprobes_text_end"); + if (! sess.sym_stext) + sess.sym_stext = lookup_symbol_address (km, "_stext"); + + if (sess.verbose > 2) + { + clog << "control symbols:" + // abbreviate the names - they're for our debugging only anyway + << " kts: 0x" << hex << sess.sym_kprobes_text_start + << " kte: 0x" << sess.sym_kprobes_text_end + << " stext: 0x" << sess.sym_stext + << dec << endl; + } + } } - - Dwfl_Module* km = 0; - kern_dw->iterate_over_modules(&query_kernel_module, &km); - if (km) + else if (get_param (parameters, TOK_PROCESS, module_name)) { - if (! sess.sym_kprobes_text_start) - sess.sym_kprobes_text_start = lookup_symbol_address (km, "__kprobes_text_start"); - if (! sess.sym_kprobes_text_end) - sess.sym_kprobes_text_end = lookup_symbol_address (km, "__kprobes_text_end"); - if (! sess.sym_stext) - sess.sym_stext = lookup_symbol_address (km, "_stext"); - - if (sess.verbose > 2) + // user-space target; we use one dwflpp instance per module name + // (= program or shared library) + if (user_dw.find(module_name) == user_dw.end()) { - clog << "control symbols:" - // abbreviate the names - they're for our debugging only anyway - << " kts: 0x" << hex << sess.sym_kprobes_text_start - << " kte: 0x" << sess.sym_kprobes_text_end - << " stext: 0x" << sess.sym_stext - << dec << endl; + dw = new dwflpp(sess); + // XXX: PR 3498 + dw->setup_user(module_name); + user_dw[module_name] = dw; } + else + dw = user_dw[module_name]; } - dwflpp* dw = kern_dw; + dwarf_query q(sess, base, location, *dw, parameters, finished_results); - if (q.has_absolute) + + // XXX: kernel.statement.absolute is a special case that requires no + // dwfl processing. This code should be in a separate builder. + + if (q.has_kernel && q.has_absolute) { // assert guru mode for absolute probes if (! q.base_probe->privileged) @@ -4913,7 +5000,6 @@ dwarf_builder::build(systemtap_session & sess, return; } - // dw->iterate_over_modules(&query_module, &q); dw->query_modules(&q); } @@ -8455,7 +8541,7 @@ register_standard_tapsets(systemtap_session & s) s.pattern_root->bind("perfmon")->bind_str("counter") ->bind(new perfmon_builder()); - // dwarf-based kernel/module parts + // dwarf-based kprobe/uprobe parts dwarf_derived_probe::register_patterns(s.pattern_root); // XXX: user-space starter set -- cgit From 91af0778bb5082d46270ff38f33db4054cbee822 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Wed, 23 Jul 2008 11:33:26 -0400 Subject: PR4225: support intermingled process/kernel/module probes without screwing up module cache --- tapsets.cxx | 299 +++++++++++++++++++++++------------------------------------- 1 file changed, 114 insertions(+), 185 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index dc7a2b9e..87ba8911 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -675,13 +675,8 @@ struct dwflpp void get_module_dwarf(bool required = false, bool report = true) { - if (!module_dwarf && mod_info->dwarf_status != info_absent) - { - if (!sess.ignore_dwarf) - module_dwarf = dwfl_module_getdwarf(module, &module_bias); - mod_info->dwarf_status = (module_dwarf ? info_present : info_absent); - } - + module_dwarf = dwfl_module_getdwarf(module, &module_bias); + mod_info->dwarf_status = (module_dwarf ? info_present : info_absent); if (!module_dwarf && report) { string msg = "cannot find "; @@ -878,40 +873,6 @@ struct dwflpp { } - // Called by dwfl_linux_kernel_report_offline(). We may not have - // dwarf info for the kernel and/or modules, so remember this - // module's pathname in case we need to extract elf info from it. - // (Currently, we get all the elf info we need via elfutils -- if the - // elf file exists -- so remembering the pathname isn't strictly needed. - // But we still need to handle the case where there's no vmlinux.) - - static systemtap_session* this_session; // XXX: used only due to elfutils shortcoming - - static int pathname_caching_callback(const char *name, const char *path) - { - module_info *mi = new module_info(name); - assert (this_session); - this_session->module_cache->cache[name] = mi; - - if (this_session->ignore_vmlinux && path && name == TOK_KERNEL) - { - // report_kernel() in elfutils found vmlinux, but pretend it didn't. - // Given a non-null path, returning 1 means keep reporting modules. - mi->dwarf_status = info_absent; - return 1; - } - else if (path) - { - mi->elf_path = path; - return 1; - } - - // No vmlinux. Here returning 0 to report_kernel() means go ahead - // and keep reporting modules. - assert(name == TOK_KERNEL); - mi->dwarf_status = info_absent; - return 0; - } void setup_kernel(bool debuginfo_needed = true) { @@ -940,24 +901,9 @@ struct dwflpp throw semantic_error ("cannot open dwfl"); dwfl_report_begin (dwfl); - int (*callback)(const char *name, const char *path); - if (sess.consult_symtab && !sess.module_cache->paths_collected) - { - callback = pathname_caching_callback; - sess.module_cache->paths_collected = true; - } - else - callback = NULL; - - // XXX: we should not need to set this static variable just - // for the callback. The following elfutils routine should - // take some void* parameter to pass context to the callback. - this_session = & sess; int rc = dwfl_linux_kernel_report_offline (dwfl, debug_path, - /* selection predicate */ - callback); - this_session = 0; + NULL); if (debuginfo_needed) dwfl_assert (string("missing kernel ") + @@ -1006,24 +952,16 @@ struct dwflpp throw semantic_error ("cannot open dwfl"); dwfl_report_begin (dwfl); - // XXX: pathname caching? - // XXX: need to map module_name to fully-qualified directory names, // searching PATH etc. // XXX: should support buildid-based naming - // XXX: we should not need to set this static variable just - // for the callback. The following elfutils routine should - // take some void* parameter to pass context to the callback. - this_session = & sess; Dwfl_Module *mod = dwfl_report_offline (dwfl, module_name.c_str(), module_name.c_str(), -1); // XXX: save mod! - - this_session = 0; if (debuginfo_needed) dwfl_assert (string("missing process ") + @@ -1045,68 +983,22 @@ struct dwflpp // ----------------------------------------------------------------- - static int module_caching_callback(Dwfl_Module * mod, - void **, - const char *name, - Dwarf_Addr addr, - void *param) - { - systemtap_session *sess = static_cast(param); - module_cache_t *cache = sess->module_cache; - module_info *mi = NULL; - - assert (cache); - - if (sess->ignore_vmlinux && name == TOK_KERNEL) - // This wouldn't be called for vmlinux if vmlinux weren't there. - return DWARF_CB_OK; - - if (cache->paths_collected) - mi = cache->cache[name]; - if (!mi) - { - mi = new module_info(name); - cache->cache[name] = mi; - } - mi->mod = mod; - mi->addr = addr; - return DWARF_CB_OK; - } - - void cache_modules_dwarf() - { - if (!sess.module_cache->dwarf_collected) - { - ptrdiff_t off = 0; - do - { - if (pending_interrupts) return; - off = dwfl_getmodules (dwfl, module_caching_callback, - & sess, off); - } - while (off > 0); - dwfl_assert("dwfl_getmodules", off == 0); - sess.module_cache->dwarf_collected = true; - } - } - - void iterate_over_modules(int (* callback)(Dwfl_Module *, module_info *, + void iterate_over_modules(int (* callback)(Dwfl_Module *, void **, const char *, Dwarf_Addr, void *), - void * data) + dwarf_query *data) { - cache_modules_dwarf(); - - map::iterator i; - for (i = sess.module_cache->cache.begin(); i != sess.module_cache->cache.end(); i++) + ptrdiff_t off = 0; + do { if (pending_interrupts) return; - module_info *mi = i->second; - int rc = callback (mi->mod, mi, mi->name, mi->addr, data); - if (rc != DWARF_CB_OK) break; + off = dwfl_getmodules (dwfl, callback, data, off); } + while (off > 0); + dwfl_assert("dwfl_getmodules", off == 0); } + // Defined after dwarf_query void query_modules(dwarf_query *q); @@ -2320,10 +2212,6 @@ struct dwflpp }; -systemtap_session* dwflpp::this_session = 0; // XXX: used only due to elfutils shortcoming - - - enum function_spec_type @@ -2420,6 +2308,8 @@ struct base_query // Extracted parameters. bool has_kernel; + bool has_module; + bool has_process; string module_val; // has_kernel => module_val = "kernel" virtual void handle_query_module() = 0; @@ -2435,17 +2325,17 @@ base_query::base_query(systemtap_session & sess, : sess(sess), base_probe(base_probe), base_loc(base_loc), dw(dw), results(results) { - has_kernel = has_null_param(params, TOK_KERNEL); + has_kernel = has_null_param (params, TOK_KERNEL); if (has_kernel) module_val = "kernel"; + + has_module = get_string_param (params, TOK_MODULE, module_val); + if (has_module) + has_process = false; else - { - bool has_module_or_process = - get_string_param(params, TOK_MODULE, module_val) || - get_string_param(params, TOK_PROCESS, module_val); - assert (has_module_or_process); // no other options are possible by construction - (void) has_module_or_process; // for -DNDEBUG - } + has_process = get_string_param(params, TOK_PROCESS, module_val); + + assert (has_kernel || has_process || has_module); } bool @@ -2941,6 +2831,10 @@ dwarf_query::handle_query_module() void dwarf_query::build_blacklist() { + // No blacklist for userspace. + if (has_process) + return; + // We build up the regexps in these strings // Add ^ anchors at the front; $ will be added just before regcomp. @@ -3149,9 +3043,11 @@ dwarf_query::parse_function_spec(string & spec) } +#if 0 // Forward declaration. -static int query_kernel_module (Dwfl_Module *, module_info *, const char *, +static int query_kernel_module (Dwfl_Module *, void **, const char *, Dwarf_Addr, void *); +#endif // XXX: pull this into dwflpp @@ -3177,6 +3073,9 @@ dwarf_query::blacklisted_p(const string& funcname, const string& section, Dwarf_Addr addr) { + if (has_process) + return false; // no blacklist for userspace + if (section.substr(0, 6) == string(".init.") || section.substr(0, 6) == string(".exit.") || section.substr(0, 9) == string(".devinit.") || @@ -3304,8 +3203,10 @@ dwarf_query::add_probe_point(const string& funcname, clog << "probe " << funcname << "@" << filename << ":" << line; if (string(module) == TOK_KERNEL) clog << " kernel"; - else + else if (has_module) clog << " module=" << module; + else if (has_process) + clog << " process=" << module; if (reloc_section != "") clog << " reloc=" << reloc_section; if (blacklist_section != "") clog << " section=" << blacklist_section; clog << " pc=0x" << hex << addr << dec; @@ -3779,9 +3680,10 @@ query_cu (Dwarf_Die * cudie, void * arg) } +#if 0 static int query_kernel_module (Dwfl_Module *mod, - module_info *, + void **, const char *name, Dwarf_Addr, void *arg) @@ -3795,6 +3697,8 @@ query_kernel_module (Dwfl_Module *mod, } return DWARF_CB_OK; } +#endif + static void validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q) @@ -3861,17 +3765,61 @@ validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q) << "\n"; } + + +static Dwarf_Addr +lookup_symbol_address (Dwfl_Module *m, const char* wanted) +{ + int syments = dwfl_module_getsymtab(m); + assert(syments); + for (int i = 1; i < syments; ++i) + { + GElf_Sym sym; + const char *name = dwfl_module_getsym(m, i, &sym, NULL); + if (name != NULL && strcmp(name, wanted) == 0) + return sym.st_value; + } + + return 0; +} + + + static int query_module (Dwfl_Module *mod, - module_info *mi, + void **, const char *name, Dwarf_Addr, void *arg) { - base_query * q = static_cast(arg); + base_query *q = static_cast(arg); try { + module_info* mi = q->sess.module_cache->cache[name]; + if (mi == 0) + { + mi = q->sess.module_cache->cache[name] = new module_info(name); + + const char *path = NULL; // XXX: unbreak this + + if (q->sess.ignore_vmlinux && path && name == TOK_KERNEL) + { + // report_kernel() in elfutils found vmlinux, but pretend it didn't. + // Given a non-null path, returning 1 means keep reporting modules. + mi->dwarf_status = info_absent; + } + else if (path) + { + mi->elf_path = path; + } + + // No vmlinux. Here returning 0 to report_kernel() means go ahead + // and keep reporting modules. + mi->dwarf_status = info_absent; + } + // OK, enough of that module_info caching business. + q->dw.focus_on_module(mod, mi); // If we have enough information in the pattern to skip a module and @@ -3888,14 +3836,28 @@ query_module (Dwfl_Module *mod, if (mod) validate_module_elf(mod, name, q); else + assert(q->has_kernel); // and no vmlinux to examine + + if (q->sess.verbose>2) + cerr << "focused on module '" << q->dw.module_name << "'\n"; + + + // Collect a few kernel addresses. XXX: these belong better + // to the sess.module_info["kernel"] struct. + if (q->dw.module_name == TOK_KERNEL) { - assert(q->has_kernel); // and no vmlinux to examine - if (q->sess.verbose>2) - cerr << "focused on module '" << q->dw.module_name << "'\n"; + if (! q->sess.sym_kprobes_text_start) + q->sess.sym_kprobes_text_start = lookup_symbol_address (mod, "__kprobes_text_start"); + if (! q->sess.sym_kprobes_text_end) + q->sess.sym_kprobes_text_end = lookup_symbol_address (mod, "__kprobes_text_end"); + if (! q->sess.sym_stext) + q->sess.sym_stext = lookup_symbol_address (mod, "_stext"); } + // Finally, search the module for matches of the probe point. q->handle_query_module(); + // If we know that there will be no more matches, abort early. if (q->dw.module_name_final_match(q->module_val)) return DWARF_CB_ABORT; @@ -3912,20 +3874,7 @@ query_module (Dwfl_Module *mod, void dwflpp::query_modules(dwarf_query *q) { - string name = q->module_val; - if (name_has_wildcard(name)) - iterate_over_modules(&query_module, q); - else - { - cache_modules_dwarf(); - - map::iterator i = sess.module_cache->cache.find(name); - if (i != sess.module_cache->cache.end()) - { - module_info *mi = i->second; - query_module(mi->mod, mi, name.c_str(), mi->addr, q); - } - } + iterate_over_modules(&query_module, q); } struct var_expanding_copy_visitor: public deep_copy_visitor @@ -4419,7 +4368,7 @@ dwarf_derived_probe::join_group (systemtap_session& s) dwarf_derived_probe::dwarf_derived_probe(const string& funcname, const string& filename, int line, - // module & section speficy a relocation + // module & section specify a relocation // base for , unless section=="" // (equivalently module=="kernel") const string& module, @@ -4485,11 +4434,15 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, // number any particular match of the wildcards. vector comps; - comps.push_back - (module == TOK_KERNEL - ? new probe_point::component(TOK_KERNEL) - : new probe_point::component(TOK_MODULE, new literal_string(module))); - + if (q.has_kernel) + comps.push_back (new probe_point::component(TOK_KERNEL)); + else if(q.has_module) + comps.push_back (new probe_point::component(TOK_MODULE, new literal_string(module))); + else if(q.has_process) + comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(module))); + else + assert (0); + string fn_or_stmt; if (q.has_function_str || q.has_function_num) fn_or_stmt = "function"; @@ -4884,26 +4837,6 @@ dwarf_derived_probe_group::emit_module_exit (systemtap_session& s) } - -static Dwarf_Addr -lookup_symbol_address (Dwfl_Module *m, const char* wanted) -{ - int syments = dwfl_module_getsymtab(m); - assert(syments); - for (int i = 1; i < syments; ++i) - { - GElf_Sym sym; - const char *name = dwfl_module_getsym(m, i, &sym, NULL); - if (name != NULL && strcmp(name, wanted) == 0) - return sym.st_value; - } - - return 0; -} - - - - void dwarf_builder::build(systemtap_session & sess, probe * base, @@ -4933,6 +4866,7 @@ dwarf_builder::build(systemtap_session & sess, } dw = kern_dw; +#if 0 // Extract some kernel-side blacklist/relocation information. // XXX: This really should be per-module rather than per-kernel, since // .ko's may conceivably contain __kprobe-marked code @@ -4940,12 +4874,6 @@ dwarf_builder::build(systemtap_session & sess, kern_dw->iterate_over_modules(&query_kernel_module, &km); if (km) { - if (! sess.sym_kprobes_text_start) - sess.sym_kprobes_text_start = lookup_symbol_address (km, "__kprobes_text_start"); - if (! sess.sym_kprobes_text_end) - sess.sym_kprobes_text_end = lookup_symbol_address (km, "__kprobes_text_end"); - if (! sess.sym_stext) - sess.sym_stext = lookup_symbol_address (km, "_stext"); if (sess.verbose > 2) { @@ -4957,6 +4885,7 @@ dwarf_builder::build(systemtap_session & sess, << dec << endl; } } +#endif } else if (get_param (parameters, TOK_PROCESS, module_name)) { -- cgit From 6d0f3f0cc2931c2ad29b57f4fecdde3ccc210d8c Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sat, 2 Aug 2008 16:28:50 -0400 Subject: PR4225: signs of life --- tapsets.cxx | 371 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 296 insertions(+), 75 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 55873d51..548fdf64 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2249,9 +2249,7 @@ struct dwarf_derived_probe: public derived_probe long maxactive_val; void printsig (std::ostream &o) const; - void join_group (systemtap_session& s); - void emit_probe_local_init(translator_output * o); // Pattern registration helpers. @@ -2265,6 +2263,32 @@ struct dwarf_derived_probe: public derived_probe }; +struct uprobe_derived_probe: public derived_probe +{ + bool return_p; + string module; // * => unrestricted + int pid; // 0 => unrestricted + string section; // empty => absolute address + Dwarf_Addr address; + // bool has_maxactive; + // long maxactive_val; + uprobe_derived_probe (const string& function, + const string& filename, + int line, + const string& module, + int pid, + const string& section, + Dwarf_Addr dwfl_addr, + Dwarf_Addr addr, + dwarf_query & q, + Dwarf_Die* scope_die); + + void printsig (std::ostream &o) const; + void join_group (systemtap_session& s); +}; + + + struct dwarf_derived_probe_group: public derived_probe_group { private: @@ -3165,7 +3189,6 @@ dwarf_query::add_probe_point(const string& funcname, Dwarf_Die* scope_die, Dwarf_Addr addr) { - dwarf_derived_probe *probe = NULL; string reloc_section; // base section for relocation purposes Dwarf_Addr reloc_addr = addr; // relocated string blacklist_section; // linking section for blacklist purposes @@ -3226,9 +3249,20 @@ dwarf_query::add_probe_point(const string& funcname, if (! bad) { sess.unwindsym_modules.insert (module); - probe = new dwarf_derived_probe(funcname, filename, line, - module, reloc_section, addr, reloc_addr, *this, scope_die); - results.push_back(probe); + + if (has_process) + { + results.push_back (new uprobe_derived_probe(funcname, filename, line, + module, 0, reloc_section, addr, reloc_addr, + *this, scope_die)); + } + else + { + assert (has_kernel || has_module); + results.push_back (new dwarf_derived_probe(funcname, filename, line, + module, reloc_section, addr, reloc_addr, + *this, scope_die)); + } } } @@ -4350,7 +4384,7 @@ dwarf_derived_probe::printsig (ostream& o) const // function instances. This is distinct from the verbose/clog // output, since this part goes into the cache hash calculations. sole_location()->print (o); - o << " /* pc=0x" << hex << addr << dec << " */"; + o << " /* pc=" << section << "+0x" << hex << addr << dec << " */"; printsig_nested (o); } @@ -4720,7 +4754,7 @@ dwarf_derived_probe_group::emit_module_init (systemtap_session& s) s.op->newline() << "struct stap_dwarf_kprobe *kp = & stap_dwarf_kprobes[i];"; s.op->newline() << "unsigned long relocated_addr = _stp_module_relocate (sdp->module, sdp->section, sdp->address);"; s.op->newline() << "if (relocated_addr == 0) continue;"; // quietly; assume module is absent - s.op->newline() << "probe_point = sdp->pp;"; + s.op->newline() << "probe_point = sdp->pp;"; // for error messages s.op->newline() << "if (sdp->return_p) {"; s.op->newline(1) << "kp->u.krp.kp.addr = (void *) relocated_addr;"; s.op->newline() << "if (sdp->maxactive_p) {"; @@ -5317,21 +5351,7 @@ void task_finder_derived_probe_group::create_session_group (systemtap_session& s) { if (! s.task_finder_derived_probes) - { - s.task_finder_derived_probes = new task_finder_derived_probe_group(); - - // Make sure we've got the stuff we need early in the output code. - embeddedcode *ec = new embeddedcode; - ec->tok = NULL; - ec->code = string("#if ! defined(CONFIG_UTRACE)\n") - + string("#error \"Need CONFIG_UTRACE!\"\n") - + string("#endif\n") - + string("#include \n") - + string("#include \n") - + string("#include \"task_finder.c\"\n"); - - s.embeds.push_back(ec); - } + s.task_finder_derived_probes = new task_finder_derived_probe_group(); } @@ -5343,8 +5363,7 @@ task_finder_derived_probe_group::emit_module_init (systemtap_session& s) s.op->newline() << "rc = stap_start_task_finder();"; s.op->newline() << "if (rc) {"; - s.op->indent(1); - s.op->newline() << "stap_stop_task_finder();"; + s.op->newline(1) << "stap_stop_task_finder();"; s.op->newline(-1) << "}"; } @@ -6078,15 +6097,6 @@ utrace_derived_probe_group::emit_module_exit (systemtap_session& s) // user-space probes // ------------------------------------------------------------------------ -struct uprobe_derived_probe: public derived_probe -{ - uint64_t process, address; - bool return_p; - uprobe_derived_probe (systemtap_session &s, probe* p, probe_point* l, - uint64_t, uint64_t, bool); - void join_group (systemtap_session& s); -}; - struct uprobe_derived_probe_group: public generic_dpg { @@ -6097,12 +6107,119 @@ public: }; -uprobe_derived_probe::uprobe_derived_probe (systemtap_session &s, - probe* p, probe_point* l, - uint64_t pp, uint64_t aa, bool rr): - derived_probe(p, l), process(pp), address(aa), return_p (rr) +uprobe_derived_probe::uprobe_derived_probe (const string& function, + const string& filename, + int line, + const string& module, + int pid, + const string& section, + Dwarf_Addr dwfl_addr, + Dwarf_Addr addr, + dwarf_query & q, + Dwarf_Die* scope_die /* may be null */): + derived_probe (q.base_probe, new probe_point (*q.base_loc) /* .components soon rewritten */ ), + return_p (q.has_return), module (module), pid (pid), section (section), address (addr) { - s.need_uprobes = true; + // Assert relocation invariants + if (section == "" && dwfl_addr != addr) // addr should be absolute + throw semantic_error ("missing relocation base against", q.base_loc->tok); + if (section != "" && dwfl_addr == addr) // addr should be an offset + throw semantic_error ("inconsistent relocation address", q.base_loc->tok); + + // For now, we don't try to handle relocatable addresses + if (section != "") throw semantic_error ("cannot relocate user-space probes yet", q.base_loc->tok); + + this->tok = q.base_probe->tok; + + // Make a target-variable-expanded copy of the probe body + if (!null_die(scope_die)) + { + dwarf_var_expanding_copy_visitor v (q, scope_die, dwfl_addr); // XXX: user-space deref's! + require (&v, &(this->body), this->body); + + // If during target-variable-expanding the probe, we added a new block + // of code, add it to the start of the probe. + if (v.add_block) + this->body = new block(v.add_block, this->body); + + // If when target-variable-expanding the probe, we added a new + // probe, add it in a new file to the list of files to be processed. + if (v.add_probe) + { + stapfile *f = new stapfile; + f->probes.push_back(v.add_probe); + q.sess.files.push_back(f); + } + } + // else - null scope_die - $target variables will produce an error during translate phase + + // Reset the sole element of the "locations" vector as a + // "reverse-engineered" form of the incoming (q.base_loc) probe + // point. This allows a user to see what function / file / line + // number any particular match of the wildcards. + + vector comps; + if(q.has_process) + comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(module))); + else + assert (0); + + string fn_or_stmt; + if (q.has_function_str || q.has_function_num) + fn_or_stmt = "function"; + else + fn_or_stmt = "statement"; + + if (q.has_function_str || q.has_statement_str) + { + string retro_name = function; + if (filename != "") + retro_name += ("@" + string (filename)); + if (line != -1) + retro_name += (":" + lex_cast (line)); + comps.push_back + (new probe_point::component + (fn_or_stmt, new literal_string (retro_name))); + } + else if (q.has_function_num || q.has_statement_num) + { + Dwarf_Addr retro_addr; + if (q.has_function_num) + retro_addr = q.function_num_val; + else + retro_addr = q.statement_num_val; + comps.push_back (new probe_point::component + (fn_or_stmt, + new literal_number(retro_addr))); // XXX: should be hex if possible + + if (q.has_absolute) + comps.push_back (new probe_point::component (TOK_ABSOLUTE)); + } + + if (q.has_call) + comps.push_back (new probe_point::component(TOK_CALL)); + if (q.has_inline) + comps.push_back (new probe_point::component(TOK_INLINE)); + if (return_p) + comps.push_back (new probe_point::component(TOK_RETURN)); + /* + if (has_maxactive) + comps.push_back (new probe_point::component + (TOK_MAXACTIVE, new literal_number(maxactive_val))); + */ + + // Overwrite it. + this->sole_location()->components = comps; +} + + +void +uprobe_derived_probe::printsig (ostream& o) const +{ + // Same as dwarf_derived_probe. + sole_location()->print (o); + o << " /* pc=" << section << "+0x" << hex << address << dec << " */"; + printsig_nested (o); } @@ -6112,6 +6229,7 @@ uprobe_derived_probe::join_group (systemtap_session& s) if (! s.uprobe_derived_probes) s.uprobe_derived_probes = new uprobe_derived_probe_group (); s.uprobe_derived_probes->enroll (this); + task_finder_derived_probe_group::create_session_group (s); } @@ -6124,6 +6242,7 @@ struct uprobe_builder: public derived_probe_builder literal_map_t const & parameters, vector & finished_results) { +#if 0 int64_t process, address; bool b1 = get_param (parameters, TOK_PROCESS, process); @@ -6135,6 +6254,7 @@ struct uprobe_builder: public derived_probe_builder finished_results.push_back(new uprobe_derived_probe(sess, base, location, process, address, rr)); +#endif } }; @@ -6145,29 +6265,43 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) if (probes.empty()) return; s.op->newline() << "/* ---- user probes ---- */"; + s.need_uprobes = true; // Ask buildrun.cxx to build extra module if needed + // If uprobes isn't in the kernel, pull it in from the runtime. s.op->newline() << "#if defined(CONFIG_UPROBES) || defined(CONFIG_UPROBES_MODULE)"; s.op->newline() << "#include "; s.op->newline() << "#else"; s.op->newline() << "#include \"uprobes/uprobes.h\""; s.op->newline() << "#endif"; + s.op->newline() << "#include \"task_finder.c\""; + + s.op->newline() << "#ifndef MAXUPROBES"; + s.op->newline() << "#define MAXUPROBES 100"; // maximum possible armed uprobes per process() probe point + s.op->newline() << "#endif"; s.op->newline() << "struct stap_uprobe {"; s.op->newline(1) << "union { struct uprobe up; struct uretprobe urp; };"; - s.op->newline() << "unsigned registered_p:1;"; - s.op->newline() << "unsigned return_p:1;"; - s.op->newline() << "unsigned long process;"; + s.op->newline() << "int spec_index;"; // index into stap_uprobe_specs; <0 == free && unregistered + s.op->newline(-1) << "};"; // kept in per-uprobe_spec pointer arrays + + s.op->newline() << "struct stap_uprobe_spec {"; + s.op->newline(1) << "struct stap_uprobe probes [MAXUPROBES];"; // XXX: make dynamic or .maxactive(NN) + s.op->newline() << "struct mutex probes_lock;"; + s.op->newline() << "struct stap_task_finder_target finder;"; s.op->newline() << "unsigned long address;"; s.op->newline() << "const char *pp;"; s.op->newline() << "void (*ph) (struct context*);"; - s.op->newline(-1) << "} stap_uprobes [] = {"; + s.op->newline() << "unsigned return_p:1;"; + s.op->newline(-1) << "} stap_uprobe_specs [] = {"; s.op->indent(1); for (unsigned i =0; inewline() << "{"; + s.op->line() << " .finder = {" + << " .pathname=" << lex_cast_qstring(p->module) << ", " + << "},"; s.op->line() << " .address=0x" << hex << p->address << dec << "UL,"; - s.op->line() << " .process=" << p->process << ","; s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ","; s.op->line() << " .ph=&" << p->name << ","; if (p->return_p) s.op->line() << " .return_p=1,"; @@ -6175,25 +6309,110 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) } s.op->newline(-1) << "};"; - s.op->newline(); s.op->newline() << "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"); - s.op->newline() << "c->probe_point = sup->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() << "(*sup->ph) (c);"; + s.op->newline() << "(*sups->ph) (c);"; common_probe_entryfn_epilogue (s.op); s.op->newline(-1) << "}"; s.op->newline() << "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"); - s.op->newline() << "c->probe_point = sup->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() << "(*sup->ph) (c);"; + s.op->newline() << "(*sups->ph) (c);"; common_probe_entryfn_epilogue (s.op); s.op->newline(-1) << "}"; + + // XXX: This sort of plain process.begin/end callback will only work + // for uprobes on unrelocatable executables. + // + // NB: Because these utrace callbacks only occur before / after + // userspace instructions run, there is no concurrency control issue + // between active uprobe callbacks and these registration / + // unregistration pieces. + + // We protect the stap_uprobe->spec_index (which also serves as a + // free/busy flag) value with the outer protective probes_lock + // mutex, to protect it against concurrent registration / + // unregistration. XXX: This should become less naive and let the + // mutex only protect stap_uprobe slot allocation and let the uprobe + // calls occur outside the critical section. + + s.op->newline(); + s.op->newline() << "int stap_uprobe_process_found (struct task_struct *tsk, int register_p, int process_p, struct stap_task_finder_target *tgt) {"; + s.op->newline(1) << "struct stap_uprobe_spec *sups = container_of(tgt, struct stap_uprobe_spec, finder);"; + s.op->newline() << "int spec_index = (sups - stap_uprobe_specs);"; + s.op->newline() << "int handled_p = 0;"; + s.op->newline() << "int rc = 0;"; + s.op->newline() << "int i;"; + // s.op->newline() << "printk (KERN_EMERG \"probe %d %d %d %p\\n\", tsk->tgid, register_p, process_p, tgt);"; + s.op->newline() << "if (! process_p) return 0;"; // we don't care about threads + s.op->newline() << "mutex_lock (& sups->probes_lock);"; + + s.op->newline() << "for (i=0; inewline(1) << "struct stap_uprobe *sup = & sups->probes[i];"; + + // register new uprobe + s.op->newline() << "if (register_p && sup->spec_index < 0) {"; + s.op->newline(1) << "sup->spec_index = spec_index;"; + s.op->newline() << "if (sups->return_p) {"; + s.op->newline(1) << "sup->urp.u.pid = tsk->tgid;"; + s.op->newline() << "sup->urp.u.vaddr = sups->address;"; + s.op->newline() << "sup->urp.handler = &enter_uretprobe_probe;"; + s.op->newline() << "rc = register_uretprobe (& sup->urp);"; + s.op->newline(-1) << "} else {"; + s.op->newline(1) << "sup->up.pid = tsk->tgid;"; + s.op->newline() << "sup->up.vaddr = sups->address;"; + s.op->newline() << "sup->up.handler = &enter_uprobe_probe;"; + s.op->newline() << "rc = register_uprobe (& sup->up);"; + s.op->newline(-1) << "}"; + + s.op->newline() << "if (rc) {"; // failed to register + s.op->newline(1) << "sup->spec_index = -1;"; + s.op->newline(-1) << "} else {"; + s.op->newline(1) << "handled_p = 1;"; // success + s.op->newline(-1) << "}"; + s.op->newline() << "break;"; + + // unregister old uprobe + s.op->newline(-1) << "} else if (!register_p && " + << "((sups->return_p && sup->urp.u.pid == tsk->tgid) ||" // dying uretprobe + << "(!sups->return_p && sup->up.pid == tsk->tgid))) {"; // dying uprobe + s.op->newline(1) << "sup->spec_index = -1;"; + s.op->newline() << "if (sups->return_p) {"; + s.op->newline(1) << "unregister_uretprobe (& sup->urp);"; + s.op->newline(-1) << "} else {"; + s.op->newline(1) << "unregister_uprobe (& sup->up);"; + s.op->newline(-1) << "}"; + s.op->newline() << "handled_p = 1;"; + + s.op->newline(-1) << "}"; // if/else + + s.op->newline(-1) << "}"; // for-over-sups->probes[] loop + s.op->newline() << "mutex_unlock (& sups->probes_lock);"; + s.op->newline() << "if (! handled_p) {"; + s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {"; + s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; + s.op->newline() << "_stp_exit ();"; + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; + + s.op->newline() << "return 0;"; // XXX: or rc? + s.op->newline(-1) << "}"; + s.op->assert_0_indent(); + + s.op->newline(); } @@ -6201,33 +6420,28 @@ void uprobe_derived_probe_group::emit_module_init (systemtap_session& s) { if (probes.empty()) return; - s.op->newline() << "/* ---- user probes ---- */"; + s.op->newline() << "/* ---- " << probes.size() << " user probes ---- */"; s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; - s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];"; - s.op->newline() << "probe_point = sup->pp;"; - s.op->newline() << "if (sup->return_p) {"; - s.op->newline(1) << "sup->urp.u.pid = sup->process;"; - s.op->newline() << "sup->urp.u.vaddr = sup->address;"; - s.op->newline() << "sup->urp.handler = &enter_uretprobe_probe;"; - s.op->newline() << "rc = register_uretprobe (& sup->urp);"; - s.op->newline(-1) << "} else {"; - s.op->newline(1) << "sup->up.pid = sup->process;"; - s.op->newline() << "sup->up.vaddr = sup->address;"; - s.op->newline() << "sup->up.handler = &enter_uprobe_probe;"; - s.op->newline() << "rc = register_uprobe (& sup->up);"; + s.op->newline(1) << "struct stap_uprobe_spec *sups = & stap_uprobe_specs[i];"; + s.op->newline() << "probe_point = sups->pp;"; // for error messages + s.op->newline() << "mutex_init (&sups->probes_lock);"; + s.op->newline() << "for (j=0; jnewline(1) << "struct stap_uprobe *sup = &sups->probes[j];"; + s.op->newline() << "sup->spec_index = -1;"; // free slot s.op->newline(-1) << "}"; + s.op->newline() << "sups->finder.callback = & stap_uprobe_process_found;"; + s.op->newline() << "rc = stap_register_task_finder_target (& sups->finder);"; s.op->newline() << "if (rc) {"; - s.op->newline(1) << "for (j=i-1; j>=0; j--) {"; // partial rollback - s.op->newline(1) << "struct stap_uprobe *sup2 = & stap_uprobes[j];"; - s.op->newline() << "if (sup2->return_p) unregister_uretprobe (²->urp);"; - s.op->newline() << "else unregister_uprobe (²->up);"; - // NB: we don't have to clear sup2->registered_p, since the module_exit code is - // not run for this early-abort case. + s.op->newline(1) << "for (j=i-1; j>=0; j--) {"; + // NB: there is no need (XXX: nor any way) to clean up any finders + // already registered, since mere registration does not cause any + // utrace or memory allocation actions. That happens only later, + // once the task finder engine starts running. So, for a partial + // initialization requiring unwind, we need do only this: + s.op->newline(1) << "mutex_destroy (&sups->probes_lock);"; s.op->newline(-1) << "}"; - s.op->newline() << "break;"; // don't attempt to register any more probes s.op->newline(-1) << "}"; - s.op->newline() << "else sup->registered_p = 1;"; s.op->newline(-1) << "}"; } @@ -6239,13 +6453,20 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline() << "/* ---- user probes ---- */"; s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; - s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];"; - s.op->newline() << "if (! sup->registered_p) continue;"; + s.op->newline(1) << "struct stap_uprobe_spec *sups = & stap_uprobe_specs[i];"; + // NB: there is no stap_unregister_task_finder_target call; + // important stuff like utrace cleanups are done by + // __stp_task_finder_cleanup() + s.op->newline() << "for (j=0; jnewline(1) << "struct stap_uprobe *sup = &sups->probes[j];"; + s.op->newline() << "if (sup->spec_index < 0) continue;"; // free slot + s.op->newline() << "if (sups->return_p) unregister_uretprobe (&sup->urp);"; + s.op->newline() << "else unregister_uprobe (&sup->up);"; + s.op->newline() << "sup->spec_index = -1;"; // s.op->newline() << "atomic_add (sdp->u.krp.nmissed, & skipped_count);"; // s.op->newline() << "atomic_add (sdp->u.krp.kp.nmissed, & skipped_count);"; - s.op->newline() << "if (sup->return_p) unregister_uretprobe (&sup->urp);"; - s.op->newline() << "else unregister_uprobe (&sup->up);"; - s.op->newline() << "sup->registered_p = 0;"; + s.op->newline(-1) << "}"; + s.op->newline() << "mutex_destroy (&sups->probes_lock);"; s.op->newline(-1) << "}"; } -- cgit From 48e685da27141914cff14dc6ea92aebbb74c5906 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sat, 2 Aug 2008 22:21:35 -0400 Subject: PR4225: it's alive, alive! --- tapsets.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 548fdf64..412b3b6f 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -6276,7 +6276,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "#include \"task_finder.c\""; s.op->newline() << "#ifndef MAXUPROBES"; - s.op->newline() << "#define MAXUPROBES 100"; // maximum possible armed uprobes per process() probe point + s.op->newline() << "#define MAXUPROBES 16"; // maximum possible armed uprobes per process() probe point s.op->newline() << "#endif"; s.op->newline() << "struct stap_uprobe {"; @@ -6309,7 +6309,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) } s.op->newline(-1) << "};"; - s.op->newline() << "void enter_uprobe_probe (struct uprobe *inst, struct pt_regs *regs) {"; + 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"); @@ -6321,7 +6321,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) common_probe_entryfn_epilogue (s.op); s.op->newline(-1) << "}"; - s.op->newline() << "void enter_uretprobe_probe (struct uretprobe_instance *inst, struct pt_regs *regs) {"; + 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"); @@ -6350,7 +6350,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // calls occur outside the critical section. s.op->newline(); - s.op->newline() << "int stap_uprobe_process_found (struct task_struct *tsk, int register_p, int process_p, struct stap_task_finder_target *tgt) {"; + s.op->newline() << "static int stap_uprobe_process_found (struct task_struct *tsk, int register_p, int process_p, struct stap_task_finder_target *tgt) {"; s.op->newline(1) << "struct stap_uprobe_spec *sups = container_of(tgt, struct stap_uprobe_spec, finder);"; s.op->newline() << "int spec_index = (sups - stap_uprobe_specs);"; s.op->newline() << "int handled_p = 0;"; -- cgit From 5e112f921fb7b05115f021319e18f90e68594a19 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sat, 2 Aug 2008 23:16:52 -0400 Subject: PR4225: use shared stap_uprobe[] pool in .bss --- tapsets.cxx | 68 ++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 412b3b6f..b9b4fcff 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -6278,16 +6278,18 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "#ifndef MAXUPROBES"; s.op->newline() << "#define MAXUPROBES 16"; // maximum possible armed uprobes per process() probe point s.op->newline() << "#endif"; + s.op->newline() << "#define NUMUPROBES (MAXUPROBES*" << probes.size() << ")"; + // In .bss, the shared pool of uprobe/uretprobe structs. These are + // too big to embed in the initialized .data stap_uprobe_spec array. s.op->newline() << "struct stap_uprobe {"; s.op->newline(1) << "union { struct uprobe up; struct uretprobe urp; };"; s.op->newline() << "int spec_index;"; // index into stap_uprobe_specs; <0 == free && unregistered - s.op->newline(-1) << "};"; // kept in per-uprobe_spec pointer arrays + s.op->newline(-1) << "} stap_uprobes [NUMUPROBES];"; + s.op->newline() << "DEFINE_MUTEX(stap_uprobes_lock);"; // protects against concurrent registration/unregistration s.op->newline() << "struct stap_uprobe_spec {"; - s.op->newline(1) << "struct stap_uprobe probes [MAXUPROBES];"; // XXX: make dynamic or .maxactive(NN) - s.op->newline() << "struct mutex probes_lock;"; - s.op->newline() << "struct stap_task_finder_target finder;"; + s.op->newline(1) << "struct stap_task_finder_target finder;"; s.op->newline() << "unsigned long address;"; s.op->newline() << "const char *pp;"; s.op->newline() << "void (*ph) (struct context*);"; @@ -6358,10 +6360,10 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "int i;"; // s.op->newline() << "printk (KERN_EMERG \"probe %d %d %d %p\\n\", tsk->tgid, register_p, process_p, tgt);"; s.op->newline() << "if (! process_p) return 0;"; // we don't care about threads - s.op->newline() << "mutex_lock (& sups->probes_lock);"; + s.op->newline() << "mutex_lock (& stap_uprobes_lock);"; - s.op->newline() << "for (i=0; inewline(1) << "struct stap_uprobe *sup = & sups->probes[i];"; + s.op->newline() << "for (i=0; inewline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];"; // register new uprobe s.op->newline() << "if (register_p && sup->spec_index < 0) {"; @@ -6383,12 +6385,13 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(-1) << "} else {"; s.op->newline(1) << "handled_p = 1;"; // success s.op->newline(-1) << "}"; - s.op->newline() << "break;"; + s.op->newline() << "break;"; // exit free slot search whether or not handled_p // unregister old uprobe s.op->newline(-1) << "} else if (!register_p && " << "((sups->return_p && sup->urp.u.pid == tsk->tgid) ||" // dying uretprobe << "(!sups->return_p && sup->up.pid == tsk->tgid))) {"; // dying uprobe + // XXX: or just check sup->spec_index == spec_index? s.op->newline(1) << "sup->spec_index = -1;"; s.op->newline() << "if (sups->return_p) {"; s.op->newline(1) << "unregister_uretprobe (& sup->urp);"; @@ -6396,11 +6399,13 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(1) << "unregister_uprobe (& sup->up);"; s.op->newline(-1) << "}"; s.op->newline() << "handled_p = 1;"; + // XXX: Do we need to keep searching the array for other processes, or + // can we break just like for the register-new case? s.op->newline(-1) << "}"; // if/else - s.op->newline(-1) << "}"; // for-over-sups->probes[] loop - s.op->newline() << "mutex_unlock (& sups->probes_lock);"; + s.op->newline(-1) << "}"; // stap_uprobes[] loop + s.op->newline() << "mutex_unlock (& stap_uprobes_lock);"; s.op->newline() << "if (! handled_p) {"; s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {"; s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; @@ -6420,28 +6425,27 @@ void uprobe_derived_probe_group::emit_module_init (systemtap_session& s) { if (probes.empty()) return; - s.op->newline() << "/* ---- " << probes.size() << " user probes ---- */"; + s.op->newline() << "/* ---- user probes ---- */"; + + s.op->newline() << "for (j=0; jnewline(1) << "struct stap_uprobe *sup = & stap_uprobes[j];"; + s.op->newline() << "sup->spec_index = -1;"; // free slot + s.op->newline(-1) << "}"; + s.op->newline() << "mutex_init (& stap_uprobes_lock);"; s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; s.op->newline(1) << "struct stap_uprobe_spec *sups = & stap_uprobe_specs[i];"; s.op->newline() << "probe_point = sups->pp;"; // for error messages - s.op->newline() << "mutex_init (&sups->probes_lock);"; - s.op->newline() << "for (j=0; jnewline(1) << "struct stap_uprobe *sup = &sups->probes[j];"; - s.op->newline() << "sup->spec_index = -1;"; // free slot - s.op->newline(-1) << "}"; s.op->newline() << "sups->finder.callback = & stap_uprobe_process_found;"; s.op->newline() << "rc = stap_register_task_finder_target (& sups->finder);"; - s.op->newline() << "if (rc) {"; - s.op->newline(1) << "for (j=i-1; j>=0; j--) {"; - // NB: there is no need (XXX: nor any way) to clean up any finders - // already registered, since mere registration does not cause any - // utrace or memory allocation actions. That happens only later, - // once the task finder engine starts running. So, for a partial - // initialization requiring unwind, we need do only this: - s.op->newline(1) << "mutex_destroy (&sups->probes_lock);"; - s.op->newline(-1) << "}"; - s.op->newline(-1) << "}"; + + // NB: if (rc), there is no need (XXX: nor any way) to clean up any + // finders already registered, since mere registration does not + // cause any utrace or memory allocation actions. That happens only + // later, once the task finder engine starts running. So, for a + // partial initialization requiring unwind, we need do nothing. + s.op->newline() << "if (rc) break;"; + s.op->newline(-1) << "}"; } @@ -6452,13 +6456,13 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) if (probes.empty()) return; s.op->newline() << "/* ---- user probes ---- */"; - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; - s.op->newline(1) << "struct stap_uprobe_spec *sups = & stap_uprobe_specs[i];"; // NB: there is no stap_unregister_task_finder_target call; // important stuff like utrace cleanups are done by // __stp_task_finder_cleanup() - s.op->newline() << "for (j=0; jnewline(1) << "struct stap_uprobe *sup = &sups->probes[j];"; + + s.op->newline() << "for (j=0; jnewline(1) << "struct stap_uprobe *sup = & stap_uprobes[j];"; + s.op->newline() << "struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];"; s.op->newline() << "if (sup->spec_index < 0) continue;"; // free slot s.op->newline() << "if (sups->return_p) unregister_uretprobe (&sup->urp);"; s.op->newline() << "else unregister_uprobe (&sup->up);"; @@ -6466,8 +6470,8 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) // s.op->newline() << "atomic_add (sdp->u.krp.nmissed, & skipped_count);"; // s.op->newline() << "atomic_add (sdp->u.krp.kp.nmissed, & skipped_count);"; s.op->newline(-1) << "}"; - s.op->newline() << "mutex_destroy (&sups->probes_lock);"; - s.op->newline(-1) << "}"; + + s.op->newline() << "mutex_destroy (& stap_uprobes_lock);"; } -- cgit From 104c6237f97a4a04b5473210ed6cde7509b12b08 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 7 Aug 2008 12:51:23 -0400 Subject: unbreak utrace probes by including task-finder.c --- tapsets.cxx | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index d06f7cea..4823bb9c 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -6118,6 +6118,8 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(); s.op->newline() << "/* ---- utrace probes ---- */"; + s.op->newline() << "#include \"task_finder.c\""; + s.op->newline() << "enum utrace_derived_probe_flags {"; s.op->indent(1); s.op->newline() << "UDPF_NONE,"; -- cgit From 12a7f85b2dd19fbfa34c81f6cba15015a8a2723d Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 7 Aug 2008 13:50:09 -0400 Subject: rework utrace $syscall var to expand to tapset fn, not synthetic hard-coded one --- tapsets.cxx | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 4823bb9c..ab5713b0 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -5799,14 +5799,11 @@ struct utrace_var_expanding_copy_visitor: public var_expanding_copy_visitor string probe_name; enum utrace_derived_probe_flags flags; bool target_symbol_seen; - static bool syscall_function_added; void visit_target_symbol (target_symbol* e); }; -bool utrace_var_expanding_copy_visitor::syscall_function_added = false; - utrace_derived_probe::utrace_derived_probe (systemtap_session &s, probe* p, probe_point* l, @@ -5874,27 +5871,11 @@ utrace_var_expanding_copy_visitor::visit_target_symbol (target_symbol* e) // Remember that we've seen a target variable. target_symbol_seen = true; - // Synthesize a function to grab the syscall . - if (! syscall_function_added) - { - functiondecl *fdecl = new functiondecl; - fdecl->tok = e->tok; - embeddedcode *ec = new embeddedcode; - ec->tok = e->tok; - ec->code = string("THIS->__retvalue = __stp_user_syscall_nr(CONTEXT->regs); /* pure */"); - - fdecl->name = string("_syscall_nr_get"); - fdecl->body = ec; - fdecl->type = pe_long; - sess.functions.push_back(fdecl); - syscall_function_added = true; - } - // We're going to substitute a synthesized '_syscall_nr_get' // function call for the '$syscall' reference. functioncall* n = new functioncall; n->tok = e->tok; - n->function = "_syscall_nr_get"; + n->function = "_utrace_syscall_nr"; n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session provide (this, n); -- cgit From d0a7f5a99a13b1aa347ccb11bd63a1ce50b84979 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sat, 9 Aug 2008 13:59:44 -0400 Subject: PR4225 and PR6826: expand & canonicalize executable path names process probes --- tapsets.cxx | 120 +++++++++++++++++++++++++++--------------------------------- 1 file changed, 53 insertions(+), 67 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index ab5713b0..66c9a7ac 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2357,7 +2357,11 @@ base_query::base_query(systemtap_session & sess, if (has_module) has_process = false; else - has_process = get_string_param(params, TOK_PROCESS, module_val); + { + has_process = get_string_param(params, TOK_PROCESS, module_val); + if (has_process) + module_val = find_executable (module_val); + } assert (has_kernel || has_process || has_module); } @@ -5001,6 +5005,8 @@ dwarf_builder::build(systemtap_session & sess, } else if (get_param (parameters, TOK_PROCESS, module_name)) { + module_name = find_executable (module_name); // canonicalize it + // user-space target; we use one dwflpp instance per module name // (= program or shared library) if (user_dw.find(module_name) == user_dw.end()) @@ -5536,41 +5542,11 @@ struct itrace_builder: public derived_probe_builder // If we have a path, we need to validate it. if (has_path) - { - string::size_type start_pos, end_pos; - string component; - - // Make sure it starts with '/'. - if (path[0] != '/') - throw semantic_error ("process path must start with a '/'", - location->tok); - - start_pos = 1; // get past the initial '/' - while ((end_pos = path.find('/', start_pos)) != string::npos) - { - component = path.substr(start_pos, end_pos - start_pos); - // Make sure it isn't empty. - if (component.size() == 0) - throw semantic_error ("process path component cannot be empty", - location->tok); - // Make sure it isn't relative. - else if (component == "." || component == "..") - throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok); - - start_pos = end_pos + 1; - } - component = path.substr(start_pos); - // Make sure it doesn't end with '/'. - if (component.size() == 0) - throw semantic_error ("process path cannot end with a '/'", location->tok); - // Make sure it isn't relative. - else if (component == "." || component == "..") - throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok); - } + path = find_executable (path); finished_results.push_back(new itrace_derived_probe(sess, base, location, has_path, path, pid, - single_step + single_step )); } }; @@ -5809,13 +5785,54 @@ utrace_derived_probe::utrace_derived_probe (systemtap_session &s, probe* p, probe_point* l, bool hp, string &pn, int64_t pd, enum utrace_derived_probe_flags f): - derived_probe(p, l), has_path(hp), path(pn), pid(pd), flags(f), + derived_probe (p, new probe_point (*l) /* .components soon rewritten */ ), + has_path(hp), path(pn), pid(pd), flags(f), target_symbol_seen(false) { // Make a local-variable-expanded copy of the probe body utrace_var_expanding_copy_visitor v (s, name, flags); require (&v, &(this->body), base->body); target_symbol_seen = v.target_symbol_seen; + + // Reset the sole element of the "locations" vector as a + // "reverse-engineered" form of the incoming (q.base_loc) probe + // point. This allows a user to see what program etc. + // number any particular match of the wildcards. + + vector comps; + if (hp) + comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(path))); + else + comps.push_back (new probe_point::component(TOK_PROCESS, new literal_number(pid))); + switch (flags) + { + case UDPF_THREAD_BEGIN: + comps.push_back (new probe_point::component(TOK_THREAD)); + comps.push_back (new probe_point::component(TOK_BEGIN)); + break; + case UDPF_THREAD_END: + comps.push_back (new probe_point::component(TOK_THREAD)); + comps.push_back (new probe_point::component(TOK_END)); + break; + case UDPF_SYSCALL: + comps.push_back (new probe_point::component(TOK_SYSCALL)); + break; + case UDPF_SYSCALL_RETURN: + comps.push_back (new probe_point::component(TOK_SYSCALL)); + comps.push_back (new probe_point::component(TOK_RETURN)); + break; + case UDPF_BEGIN: + comps.push_back (new probe_point::component(TOK_BEGIN)); + break; + case UDPF_END: + comps.push_back (new probe_point::component(TOK_END)); + break; + default: + assert (0); + } + + // Overwrite it. + this->sole_location()->components = comps; } @@ -5897,6 +5914,7 @@ struct utrace_builder: public derived_probe_builder bool has_path = get_param (parameters, TOK_PROCESS, path); bool has_pid = get_param (parameters, TOK_PROCESS, pid); enum utrace_derived_probe_flags flags = UDPF_NONE; + assert (has_path || has_pid); if (has_null_param (parameters, TOK_THREAD)) @@ -5921,39 +5939,7 @@ struct utrace_builder: public derived_probe_builder // If we have a path, we need to validate it. if (has_path) { - string::size_type start_pos, end_pos; - string component; - - // XXX: these checks should be done in terms of filesystem - // operations. - - // Make sure it starts with '/'. - if (path[0] != '/') - throw semantic_error ("process path must start with a '/'", - location->tok); - - start_pos = 1; // get past the initial '/' - while ((end_pos = path.find('/', start_pos)) != string::npos) - { - component = path.substr(start_pos, end_pos - start_pos); - // Make sure it isn't empty. - if (component.size() == 0) - throw semantic_error ("process path component cannot be empty", - location->tok); - // Make sure it isn't relative. - else if (component == "." || component == "..") - throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok); - - start_pos = end_pos + 1; - } - component = path.substr(start_pos); - // Make sure it doesn't end with '/'. - if (component.size() == 0) - throw semantic_error ("process path cannot end with a '/'", location->tok); - // Make sure it isn't relative. - else if (component == "." || component == "..") - throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok); - + path = find_executable (path); sess.unwindsym_modules.insert (path); } -- cgit From 0973d815afc635dfd21ae5943d84b92f61c45288 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sun, 10 Aug 2008 15:39:16 -0400 Subject: restore process(PID).statement(ADDR).absolute probe support --- tapsets.cxx | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 66c9a7ac..d9e0ebda 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2272,6 +2272,7 @@ struct uprobe_derived_probe: public derived_probe Dwarf_Addr address; // bool has_maxactive; // long maxactive_val; + uprobe_derived_probe (const string& function, const string& filename, int line, @@ -2283,6 +2284,13 @@ struct uprobe_derived_probe: public derived_probe dwarf_query & q, Dwarf_Die* scope_die); + // alternate constructor for process(PID).statement(ADDR).absolute + uprobe_derived_probe (probe *base, + probe_point *location, + int pid, + Dwarf_Addr addr, + bool return_p); + void printsig (std::ostream &o) const; void join_group (systemtap_session& s); }; @@ -6534,6 +6542,17 @@ uprobe_derived_probe::uprobe_derived_probe (const string& function, } +uprobe_derived_probe::uprobe_derived_probe (probe *base, + probe_point *location, + int pid, + Dwarf_Addr addr, + bool has_return): + derived_probe (base, location), // location is not rewritten here + return_p (has_return), pid (pid), address (addr) +{ +} + + void uprobe_derived_probe::printsig (ostream& o) const { @@ -6563,7 +6582,6 @@ struct uprobe_builder: public derived_probe_builder literal_map_t const & parameters, vector & finished_results) { -#if 0 int64_t process, address; bool b1 = get_param (parameters, TOK_PROCESS, process); @@ -6573,9 +6591,7 @@ struct uprobe_builder: public derived_probe_builder bool rr = has_null_param (parameters, TOK_RETURN); assert (b1 && b2); // by pattern_root construction - finished_results.push_back(new uprobe_derived_probe(sess, base, location, - process, address, rr)); -#endif + finished_results.push_back(new uprobe_derived_probe(base, location, process, address, rr)); } }; @@ -6621,9 +6637,12 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) { uprobe_derived_probe* p = probes[i]; s.op->newline() << "{"; - s.op->line() << " .finder = {" - << " .pathname=" << lex_cast_qstring(p->module) << ", " - << "},"; + s.op->line() << " .finder = {"; + if (p->pid != 0) + s.op->line() << " .pid=" << p->pid << ", "; + else + s.op->line() << " .pathname=" << lex_cast_qstring(p->module) << ", "; + s.op->line() << "},"; s.op->line() << " .address=0x" << hex << p->address << dec << "UL,"; s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ","; s.op->line() << " .ph=&" << p->name << ","; -- cgit From 3213d0891c826f16ba727a3e863075e2922666a0 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Mon, 11 Aug 2008 13:18:12 -0400 Subject: PR5049: prefix with "*" any filenames given in "fn@filename:line" probes --- tapsets.cxx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index d9e0ebda..48947a60 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -850,9 +850,14 @@ struct dwflpp bool cu_name_matches(string pattern) { assert(cu); - bool t = (fnmatch(pattern.c_str(), cu_name.c_str(), 0) == 0); + + // PR 5049: implicit * in front of given path pattern. + // NB: fnmatch() is used without FNM_PATHNAME. + string prefixed_pattern = string("*") + pattern; + + bool t = (fnmatch(prefixed_pattern.c_str(), cu_name.c_str(), 0) == 0); if (t && sess.verbose>3) - clog << "pattern '" << pattern << "' " + clog << "pattern '" << prefixed_pattern << "' " << "matches " << "CU '" << cu_name << "'" << "\n"; return t; @@ -1292,13 +1297,17 @@ struct dwflpp size_t nfiles; Dwarf_Files *srcfiles; + // PR 5049: implicit * in front of given path pattern. + // NB: fnmatch() is used without FNM_PATHNAME. + string prefixed_pattern = string("*") + pattern; + dwarf_assert ("dwarf_getsrcfiles", dwarf_getsrcfiles (cu, &srcfiles, &nfiles)); { for (size_t i = 0; i < nfiles; ++i) { char const * fname = dwarf_filesrc (srcfiles, i, NULL, NULL); - if (fnmatch (pattern.c_str(), fname, 0) == 0) + if (fnmatch (prefixed_pattern.c_str(), fname, 0) == 0) { filtered_srcfiles.insert (fname); if (sess.verbose>2) -- cgit From 00cf370953d55d0c79a746b4e7d65ce29266afc4 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Mon, 11 Aug 2008 19:52:00 -0400 Subject: let $$vars work even with unsupported c types (e.g., funkytown floats) --- tapsets.cxx | 52 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 17 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 5fbbb053..2f2e53a6 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1987,6 +1987,33 @@ struct dwflpp case DW_TAG_enumeration_type: case DW_TAG_base_type: + + // Reject types we can't handle in systemtap + { + dname = dwarf_diename(die); + diestr = (dname != NULL) ? dname : ""; + + Dwarf_Attribute encoding_attr; + Dwarf_Word encoding = -1; + dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, &encoding_attr), + & encoding); + if (encoding < 0) + { + // clog << "bad type1 " << encoding << " diestr" << endl; + throw semantic_error ("unsupported type (mystery encoding " + lex_cast(encoding) + ")" + + " for " + diestr); + } + + if (encoding == DW_ATE_float + || encoding == DW_ATE_complex_float + /* XXX || many others? */) + { + // clog << "bad type " << encoding << " diestr" << endl; + throw semantic_error ("unsupported type (encoding " + lex_cast(encoding) + ")" + + " for " + diestr); + } + } + ty = pe_long; if (lvalue) c_translate_store (pool, 1, module_bias, die, typedie, tail, @@ -2125,7 +2152,6 @@ struct dwflpp throw semantic_error("failed to retrieve type " "attribute for local '" + local + "'"); - /* Translate the ->bar->baz[NN] parts. */ Dwarf_Die die_mem, *die = NULL; @@ -4358,24 +4384,16 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e) tsym->tok = sym_tok; tsym->base_name = "$"; tsym->base_name += diename; - Dwarf_Attribute attr_mem; // Ignore any variable that isn't accessible. - // dwarf_attr_integrate is checked by literal_stmt_for_local - // dwarf_getlocation_addr is checked by translate_location - // but if those fail we cannot catch semantic_error. - if (dwarf_attr_integrate (&result, DW_AT_location, &attr_mem) != NULL) - { - Dwarf_Op *expr; - size_t len; - if (dwarf_getlocation_addr (&attr_mem, addr - q.dw.module_bias, - &expr, &len, 1) == 0) - continue; - this->visit_target_symbol(tsym); - pf->raw_components += diename; - pf->raw_components += "=%#x "; - pf->args.push_back(*(expression**)this->targets.top()); - } + tsym->saved_conversion_error = 0; + this->visit_target_symbol(tsym); // NB: throws nothing ... + if (! tsym->saved_conversion_error) // ... but this is how we know it happened. + { + pf->raw_components += diename; + pf->raw_components += "=%#x "; + pf->args.push_back(*(expression**)this->targets.top()); + } } while (dwarf_siblingof (&result, &result) == 0); -- cgit From 17c128f2fe920f785979aa9445eff5ac2f30d307 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 21 Aug 2008 14:31:10 -0400 Subject: pr4225: add putative shared library (ET_DYN) support --- tapsets.cxx | 74 +++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 24 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 3d4d0dc9..1003e25d 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3253,7 +3253,7 @@ dwarf_query::add_probe_point(const string& funcname, } else if (dwfl_module_relocations (dw.module) > 0) { - // This is arelocatable module; libdwfl already knows its + // This is a relocatable module; libdwfl already knows its // sections, so we can relativize addr. int idx = dwfl_module_relocate_address (dw.module, &reloc_addr); const char* r_s = dwfl_module_relocation_info (dw.module, idx, NULL); @@ -3262,12 +3262,15 @@ dwarf_query::add_probe_point(const string& funcname, blacklist_section = reloc_section; if(reloc_section == "" && dwfl_module_relocations (dw.module) == 1) - blacklist_section = this->get_blacklist_section(addr); + { + blacklist_section = this->get_blacklist_section(addr); + reloc_section = ".dynamic"; + } } else { blacklist_section = this->get_blacklist_section(addr); - reloc_section = ""; + reloc_section = ".absolute"; } if (sess.verbose > 1) @@ -6558,14 +6561,10 @@ uprobe_derived_probe::uprobe_derived_probe (const string& function, derived_probe (q.base_probe, new probe_point (*q.base_loc) /* .components soon rewritten */ ), return_p (q.has_return), module (module), pid (pid), section (section), address (addr) { - // Assert relocation invariants - if (section == "" && dwfl_addr != addr) // addr should be absolute - throw semantic_error ("missing relocation base against", q.base_loc->tok); - if (section != "" && dwfl_addr == addr) // addr should be an offset - throw semantic_error ("inconsistent relocation address", q.base_loc->tok); - - // For now, we don't try to handle relocatable addresses - if (section != "") throw semantic_error ("cannot relocate user-space probes yet", q.base_loc->tok); + // We may receive probes on two types of ELF objects: ET_EXEC or ET_DYN. + // ET_EXEC ones need no further relocation on the addr(==dwfl_addr), whereas + // ET_DYN ones do (addr += run-time mmap base address). We tell these apart + // by the incoming section value (".absolute" vs. ".dynamic"). this->tok = q.base_probe->tok; @@ -6737,6 +6736,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "struct stap_uprobe_spec {"; s.op->newline(1) << "struct stap_task_finder_target finder;"; s.op->newline() << "unsigned long address;"; + s.op->newline() << "const char *pathname;"; s.op->newline() << "const char *pp;"; s.op->newline() << "void (*ph) (struct context*);"; s.op->newline() << "unsigned return_p:1;"; @@ -6748,10 +6748,13 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "{"; s.op->line() << " .finder = {"; if (p->pid != 0) - s.op->line() << " .pid=" << p->pid << ", "; - else + s.op->line() << " .pid=" << p->pid; + else if (p->section == ".absolute") s.op->line() << " .pathname=" << lex_cast_qstring(p->module) << ", "; + // else ".dynamic" gets pathname=0, pid=0, activating task_finder "global tracing" s.op->line() << "},"; + if (p->section != ".absolute") + s.op->line() << " .pathname=" << lex_cast_qstring(p->module) << ", "; s.op->line() << " .address=0x" << hex << p->address << dec << "UL,"; s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ","; s.op->line() << " .ph=&" << p->name << ","; @@ -6785,9 +6788,8 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) common_probe_entryfn_epilogue (s.op); s.op->newline(-1) << "}"; - // XXX: This sort of plain process.begin/end callback will only work - // for uprobes on unrelocatable executables. - // + + // NB: Because these utrace callbacks only occur before / after // userspace instructions run, there is no concurrency control issue // between active uprobe callbacks and these registration / @@ -6801,14 +6803,11 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // calls occur outside the critical section. s.op->newline(); - s.op->newline() << "static int stap_uprobe_process_found (struct task_struct *tsk, int register_p, int process_p, struct stap_task_finder_target *tgt) {"; - s.op->newline(1) << "struct stap_uprobe_spec *sups = container_of(tgt, struct stap_uprobe_spec, finder);"; - s.op->newline() << "int spec_index = (sups - stap_uprobe_specs);"; + s.op->newline() << "static int stap_uprobe_change (struct task_struct *tsk, int register_p, unsigned long relocation, struct stap_uprobe_spec *sups) {"; + s.op->newline(1) << "int spec_index = (sups - stap_uprobe_specs);"; s.op->newline() << "int handled_p = 0;"; s.op->newline() << "int rc = 0;"; s.op->newline() << "int i;"; - // s.op->newline() << "printk (KERN_EMERG \"probe %d %d %d %p\\n\", tsk->tgid, register_p, process_p, tgt);"; - s.op->newline() << "if (! process_p) return 0;"; // we don't care about threads s.op->newline() << "mutex_lock (& stap_uprobes_lock);"; s.op->newline() << "for (i=0; inewline(1) << "sup->spec_index = spec_index;"; s.op->newline() << "if (sups->return_p) {"; s.op->newline(1) << "sup->urp.u.pid = tsk->tgid;"; - s.op->newline() << "sup->urp.u.vaddr = sups->address;"; + s.op->newline() << "sup->urp.u.vaddr = relocation + sups->address;"; s.op->newline() << "sup->urp.handler = &enter_uretprobe_probe;"; s.op->newline() << "rc = register_uretprobe (& sup->urp);"; s.op->newline(-1) << "} else {"; s.op->newline(1) << "sup->up.pid = tsk->tgid;"; - s.op->newline() << "sup->up.vaddr = sups->address;"; + s.op->newline() << "sup->up.vaddr = relocation + sups->address;"; s.op->newline() << "sup->up.handler = &enter_uprobe_probe;"; s.op->newline() << "rc = register_uprobe (& sup->up);"; s.op->newline(-1) << "}"; s.op->newline() << "if (rc) {"; // failed to register + s.op->newline() << "printk (KERN_WARNING \"uprobe failed pid %d addr %p rc %d\\n\", tsk->tgid, (void*)(relocation + sups->address), rc);"; s.op->newline(1) << "sup->spec_index = -1;"; s.op->newline(-1) << "} else {"; s.op->newline(1) << "handled_p = 1;"; // success @@ -6866,6 +6866,31 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(-1) << "}"; s.op->assert_0_indent(); + + // The task_finder_callback we use for ET_EXEC targets. + s.op->newline(); + s.op->newline() << "static int stap_uprobe_process_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {"; + + s.op->newline(1) << "struct stap_uprobe_spec *sups = container_of(tgt, struct stap_uprobe_spec, finder);"; + s.op->newline() << "if (! process_p) return 0;"; + s.op->newline(0) << "return stap_uprobe_change (tsk, register_p, 0, sups);"; + s.op->newline(-1) << "}"; + + // The task_finder_vm_callback we use for ET_DYN targets. + s.op->newline(); + s.op->newline() << "static int stap_uprobe_vmchange_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, int map_p, char *vm_path, unsigned long vm_start, unsigned long vm_end, unsigned long vm_pgoff) {"; + s.op->newline(1) << "struct stap_uprobe_spec *sups = container_of(tgt, struct stap_uprobe_spec, finder);"; + // 1 - shared libraries' executable segments load from offset 0 - ld.so convention + s.op->newline() << "if (vm_pgoff != 0) return 0;"; + // 2 - the shared library we're interested in + s.op->newline() << "if (strcmp (vm_path, sups->pathname)) return 0;"; + // 3 - probe address within the mapping limits; test should not fail + s.op->newline() << "if (vm_end >= sups->address) return 0;"; + s.op->newline(0) << "return stap_uprobe_change (tsk, map_p, vm_start, sups);"; + s.op->newline(-1) << "}"; + s.op->assert_0_indent(); + + s.op->newline(); } @@ -6885,7 +6910,8 @@ uprobe_derived_probe_group::emit_module_init (systemtap_session& s) s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; s.op->newline(1) << "struct stap_uprobe_spec *sups = & stap_uprobe_specs[i];"; s.op->newline() << "probe_point = sups->pp;"; // for error messages - s.op->newline() << "sups->finder.callback = & stap_uprobe_process_found;"; + s.op->newline() << "if (sups->finder.pathname) sups->finder.callback = & stap_uprobe_process_found;"; + s.op->newline() << "else if (sups->pathname) sups->finder.vm_callback = & stap_uprobe_vmchange_found;"; s.op->newline() << "rc = stap_register_task_finder_target (& sups->finder);"; // NB: if (rc), there is no need (XXX: nor any way) to clean up any -- cgit From 4b0eb1180bdebb0bd386f5f32e7e4c735e39c3bb Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 21 Aug 2008 15:44:34 -0400 Subject: pr4225: fix address miscalculation for ET_DYN objects; add more printk's in task_finder vm_callback for debugging --- tapsets.cxx | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 1003e25d..daf9d17b 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3265,6 +3265,7 @@ dwarf_query::add_probe_point(const string& funcname, { blacklist_section = this->get_blacklist_section(addr); reloc_section = ".dynamic"; + reloc_addr = addr; } } else @@ -6880,6 +6881,8 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(); s.op->newline() << "static int stap_uprobe_vmchange_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, int map_p, char *vm_path, unsigned long vm_start, unsigned long vm_end, unsigned long vm_pgoff) {"; s.op->newline(1) << "struct stap_uprobe_spec *sups = container_of(tgt, struct stap_uprobe_spec, finder);"; + s.op->newline() << "printk (KERN_INFO \"vmchange pid %d map_p %d path %s vms %p vme %p vmp %p\\n\", tsk->tgid, map_p, vm_path, (void*) vm_start, (void*) vm_end, (void*) vm_pgoff);"; + s.op->newline() << "printk (KERN_INFO \"sups %p pp %s path %s address %p\\n\", sups, sups->pp, sups->pathname ?: \"\", (void*) sups->address);"; // 1 - shared libraries' executable segments load from offset 0 - ld.so convention s.op->newline() << "if (vm_pgoff != 0) return 0;"; // 2 - the shared library we're interested in -- cgit From 8d22c6ad7250192dc526b2d9ca88b69901793e7b Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 21 Aug 2008 15:51:23 -0400 Subject: pr4225: check for null incoming vm_path --- tapsets.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index daf9d17b..409d909a 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -6886,7 +6886,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // 1 - shared libraries' executable segments load from offset 0 - ld.so convention s.op->newline() << "if (vm_pgoff != 0) return 0;"; // 2 - the shared library we're interested in - s.op->newline() << "if (strcmp (vm_path, sups->pathname)) return 0;"; + s.op->newline() << "if (vm_path == NULL || strcmp (vm_path, sups->pathname)) return 0;"; // 3 - probe address within the mapping limits; test should not fail s.op->newline() << "if (vm_end >= sups->address) return 0;"; s.op->newline(0) << "return stap_uprobe_change (tsk, map_p, vm_start, sups);"; -- cgit From c16d425a5dd60fd86efb76a429b65f87dfb5e44a Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Fri, 22 Aug 2008 12:10:17 -0400 Subject: pr4225: fix shared library address range checks; make more task_finder_vma tracing conditional on DEBUG_TASK_FINDER_VMA --- tapsets.cxx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 409d909a..7755d794 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -6881,14 +6881,18 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(); s.op->newline() << "static int stap_uprobe_vmchange_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, int map_p, char *vm_path, unsigned long vm_start, unsigned long vm_end, unsigned long vm_pgoff) {"; s.op->newline(1) << "struct stap_uprobe_spec *sups = container_of(tgt, struct stap_uprobe_spec, finder);"; - s.op->newline() << "printk (KERN_INFO \"vmchange pid %d map_p %d path %s vms %p vme %p vmp %p\\n\", tsk->tgid, map_p, vm_path, (void*) vm_start, (void*) vm_end, (void*) vm_pgoff);"; - s.op->newline() << "printk (KERN_INFO \"sups %p pp %s path %s address %p\\n\", sups, sups->pp, sups->pathname ?: \"\", (void*) sups->address);"; // 1 - shared libraries' executable segments load from offset 0 - ld.so convention s.op->newline() << "if (vm_pgoff != 0) return 0;"; // 2 - the shared library we're interested in s.op->newline() << "if (vm_path == NULL || strcmp (vm_path, sups->pathname)) return 0;"; // 3 - probe address within the mapping limits; test should not fail - s.op->newline() << "if (vm_end >= sups->address) return 0;"; + s.op->newline() << "if (vm_end <= vm_start + sups->address) return 0;"; + + s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA"; + s.op->newline() << "printk (KERN_INFO \"vmchange pid %d map_p %d path %s vms %p vme %p vmp %p\\n\", tsk->tgid, map_p, vm_path, (void*) vm_start, (void*) vm_end, (void*) vm_pgoff);"; + s.op->newline() << "printk (KERN_INFO \"sups %p pp %s path %s address %p\\n\", sups, sups->pp, sups->pathname ?: \"\", (void*) sups->address);"; + s.op->newline() << "#endif"; + s.op->newline(0) << "return stap_uprobe_change (tsk, map_p, vm_start, sups);"; s.op->newline(-1) << "}"; s.op->assert_0_indent(); -- cgit From fb84c077272764f8cb000e9b02572fb7c9cac24f Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Sun, 24 Aug 2008 08:03:53 -0400 Subject: whitespace cleanup + uprobe "?@-1" fix too --- tapsets.cxx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index f4c9a938..809792a4 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -4645,9 +4645,9 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, string retro_name = funcname; if (filename != "") { - retro_name += ("@" + string (filename)); + retro_name += ("@" + string (filename)); if (line > 0) - retro_name += (":" + lex_cast (line)); + retro_name += (":" + lex_cast (line)); } comps.push_back (new probe_point::component @@ -6614,9 +6614,11 @@ uprobe_derived_probe::uprobe_derived_probe (const string& function, { string retro_name = function; if (filename != "") - retro_name += ("@" + string (filename)); - if (line != -1) - retro_name += (":" + lex_cast (line)); + { + retro_name += ("@" + string (filename)); + if (line > 0) + retro_name += (":" + lex_cast (line)); + } comps.push_back (new probe_point::component (fn_or_stmt, new literal_string (retro_name))); -- cgit From 6f4c12753354d3e0f6b18d6290e1bf89c5084c5c Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Mon, 1 Sep 2008 13:45:25 -0400 Subject: PR6864: barest beginnings of restoring symtab-based kernel probes --- tapsets.cxx | 57 ++++++++++++++++++++++----------------------------------- 1 file changed, 22 insertions(+), 35 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index fc341a1b..3c67eed7 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -958,9 +958,6 @@ struct dwflpp throw semantic_error ("cannot open dwfl"); dwfl_report_begin (dwfl); - // XXX: need to map module_name to fully-qualified directory names, - // searching PATH etc. - // XXX: should support buildid-based naming Dwfl_Module *mod = dwfl_report_offline (dwfl, @@ -1002,6 +999,10 @@ struct dwflpp } while (off > 0); dwfl_assert("dwfl_getmodules", off == 0); + + // PR6864 XXX: For dwarfless case (if .../vmlinux is missing), then the + // "kernel" module is not reported in the loop above. However, we + // may be able to make do with symbol table data. } @@ -3876,7 +3877,7 @@ static int query_module (Dwfl_Module *mod, void **, const char *name, - Dwarf_Addr, + Dwarf_Addr addr, void *arg) { base_query *q = static_cast(arg); @@ -3888,22 +3889,30 @@ query_module (Dwfl_Module *mod, { mi = q->sess.module_cache->cache[name] = new module_info(name); - const char *path = NULL; // XXX: unbreak this + mi->mod = mod; + mi->addr = addr; - if (q->sess.ignore_vmlinux && path && name == TOK_KERNEL) + const char* debug_filename = ""; + const char* main_filename = ""; + (void) dwfl_module_info (mod, NULL, NULL, + NULL, NULL, NULL, + & main_filename, + & debug_filename); + + if (q->sess.ignore_vmlinux && name == TOK_KERNEL) { // report_kernel() in elfutils found vmlinux, but pretend it didn't. // Given a non-null path, returning 1 means keep reporting modules. mi->dwarf_status = info_absent; } - else if (path) + else if (debug_filename || main_filename) { - mi->elf_path = path; + mi->elf_path = debug_filename ?: main_filename; + } + else if (name == TOK_KERNEL) + { + mi->dwarf_status = info_absent; } - - // No vmlinux. Here returning 0 to report_kernel() means go ahead - // and keep reporting modules. - mi->dwarf_status = info_absent; } // OK, enough of that module_info caching business. @@ -5055,30 +5064,9 @@ dwarf_builder::build(systemtap_session & sess, { kern_dw = new dwflpp(sess); // XXX: PR 3498 - kern_dw->setup_kernel(); + kern_dw->setup_kernel(false); } dw = kern_dw; - -#if 0 - // Extract some kernel-side blacklist/relocation information. - // XXX: This really should be per-module rather than per-kernel, since - // .ko's may conceivably contain __kprobe-marked code - Dwfl_Module* km = 0; - kern_dw->iterate_over_modules(&query_kernel_module, &km); - if (km) - { - - if (sess.verbose > 2) - { - clog << "control symbols:" - // abbreviate the names - they're for our debugging only anyway - << " kts: 0x" << hex << sess.sym_kprobes_text_start - << " kte: 0x" << sess.sym_kprobes_text_end - << " stext: 0x" << sess.sym_stext - << dec << endl; - } - } -#endif } else if (get_param (parameters, TOK_PROCESS, module_name)) { @@ -5452,7 +5440,6 @@ module_info::get_symtab(dwarf_query *q) sess.sym_kprobes_text_end = sym_table->lookup_symbol_address("__kprobes_text_end"); sess.sym_stext = sym_table->lookup_symbol_address("_stext"); - bias = sym_table->lookup_symbol_address("_text"); } } } -- cgit From 28d29bd38253d73b3d0a0d5ea39b1fe645e66179 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Mon, 1 Sep 2008 16:11:04 -0400 Subject: test case regression fixes (25444842 vs 84182428) --- tapsets.cxx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 8f5ed287..0a7ca902 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -5063,8 +5063,8 @@ dwarf_builder::build(systemtap_session & sess, if (! kern_dw) { kern_dw = new dwflpp(sess); - // XXX: PR 3498 - kern_dw->setup_kernel(false); + // XXX: PR 3498, PR 6864 + kern_dw->setup_kernel(true); } dw = kern_dw; } @@ -5595,11 +5595,12 @@ struct itrace_builder: public derived_probe_builder vector & finished_results) { string path; - int64_t pid; + int64_t pid = 0; int single_step; bool has_path = get_param (parameters, TOK_PROCESS, path); bool has_pid = get_param (parameters, TOK_PROCESS, pid); + // XXX: PR 6445 needs !has_path && !has_pid support assert (has_path || has_pid); single_step = 1; @@ -5979,8 +5980,6 @@ struct utrace_builder: public derived_probe_builder bool has_pid = get_param (parameters, TOK_PROCESS, pid); enum utrace_derived_probe_flags flags = UDPF_NONE; - assert (has_path || has_pid); - if (has_null_param (parameters, TOK_THREAD)) { if (has_null_param (parameters, TOK_BEGIN)) @@ -6020,6 +6019,8 @@ struct utrace_builder: public derived_probe_builder if (pid < 2) throw semantic_error ("process pid must be greater than 1", location->tok); + + // XXX: could we use /proc/$pid/exe in unwindsym_modules and elsewhere? } finished_results.push_back(new utrace_derived_probe(sess, base, location, @@ -6351,7 +6352,7 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "break;"; s.op->indent(-1); } - + if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN]) { s.op->newline() << "case UDPF_SYSCALL:"; -- cgit From eebd7e0f235484ae0a6857fa41bda5dd61a2de68 Mon Sep 17 00:00:00 2001 From: Wenji Huang Date: Tue, 2 Sep 2008 01:06:16 -0400 Subject: Fix semantic error caused by -P option in nodwarf testing. --- tapsets.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index aa6a611d..c23ee8aa 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3447,7 +3447,8 @@ query_func_info (Dwarf_Addr entrypc, else { if (q->sess.prologue_searching - && !q->has_statement_str && !q->has_statement_num) // PR 2608 + && !q->has_statement_str && !q->has_statement_num + && !q->sess.ignore_vmlinux && !q->sess.ignore_dwarf) // PR 2608 { if (fi.prologue_end == 0) throw semantic_error("could not find prologue-end " -- cgit From 3568f1ddb8d66de4f377412b7b3843607dcbfc4b Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 2 Sep 2008 13:17:53 -0400 Subject: PR4225: unregistration snowballing thinko fix --- tapsets.cxx | 49 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index f71b8186..4cda930f 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3453,7 +3453,7 @@ query_func_info (Dwarf_Addr entrypc, else { if (q->sess.prologue_searching - && !q->has_statement_str && !q->has_statement_num + && !q->has_statement_str && !q->has_statement_num && !q->sess.ignore_vmlinux && !q->sess.ignore_dwarf) // PR 2608 { if (fi.prologue_end == 0) @@ -6751,6 +6751,10 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "int i;"; s.op->newline() << "mutex_lock (& stap_uprobes_lock);"; + s.op->newline() << "#ifdef DEBUG_UPROBES"; + s.op->newline() << "printk (KERN_WARNING \"uprobe idx %d change pid %d register_p %d reloc %p pp %s\\n\", spec_index, tsk->tgid, register_p, (void*) relocation, sups->pp);"; + s.op->newline() << "#endif"; + s.op->newline() << "for (i=0; inewline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];"; @@ -6761,17 +6765,23 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(1) << "sup->urp.u.pid = tsk->tgid;"; s.op->newline() << "sup->urp.u.vaddr = relocation + sups->address;"; s.op->newline() << "sup->urp.handler = &enter_uretprobe_probe;"; + s.op->newline() << "#ifdef DEBUG_UPROBES"; + s.op->newline() << "printk (KERN_WARNING \"uretprobe register pid %d addr %p\\n\", sup->urp.u.pid, (void*) sup->urp.u.vaddr);"; + s.op->newline() << "#endif"; s.op->newline() << "rc = register_uretprobe (& sup->urp);"; s.op->newline(-1) << "} else {"; s.op->newline(1) << "sup->up.pid = tsk->tgid;"; s.op->newline() << "sup->up.vaddr = relocation + sups->address;"; s.op->newline() << "sup->up.handler = &enter_uprobe_probe;"; + s.op->newline() << "#ifdef DEBUG_UPROBES"; + s.op->newline() << "printk (KERN_WARNING \"uprobe register pid %d addr %p\\n\", sup->up.pid, (void*) sup->up.vaddr);"; + s.op->newline() << "#endif"; s.op->newline() << "rc = register_uprobe (& sup->up);"; s.op->newline(-1) << "}"; s.op->newline() << "if (rc) {"; // failed to register - s.op->newline() << "printk (KERN_WARNING \"uprobe failed pid %d addr %p rc %d\\n\", tsk->tgid, (void*)(relocation + sups->address), rc);"; - s.op->newline(1) << "sup->spec_index = -1;"; + s.op->newline(1) << "printk (KERN_WARNING \"uprobe failed pid %d addr %p rc %d\\n\", tsk->tgid, (void*)(relocation + sups->address), rc);"; + s.op->newline() << "sup->spec_index = -1;"; s.op->newline(-1) << "} else {"; s.op->newline(1) << "handled_p = 1;"; // success s.op->newline(-1) << "}"; @@ -6779,15 +6789,22 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // unregister old uprobe s.op->newline(-1) << "} else if (!register_p && " + << "sup->spec_index == spec_index && " // a u[ret]probe set up for this probe point << "((sups->return_p && sup->urp.u.pid == tsk->tgid) ||" // dying uretprobe << "(!sups->return_p && sup->up.pid == tsk->tgid))) {"; // dying uprobe // XXX: or just check sup->spec_index == spec_index? - s.op->newline(1) << "sup->spec_index = -1;"; s.op->newline() << "if (sups->return_p) {"; - s.op->newline(1) << "unregister_uretprobe (& sup->urp);"; + s.op->newline(1) << "#ifdef DEBUG_UPROBES"; + s.op->newline() << "printk (KERN_WARNING \"uretprobe unregister pid %d addr %p\\n\", sup->up.pid, (void*) sup->up.vaddr);"; + s.op->newline() << "#endif"; + s.op->newline() << "unregister_uretprobe (& sup->urp);"; s.op->newline(-1) << "} else {"; - s.op->newline(1) << "unregister_uprobe (& sup->up);"; + s.op->newline(1) << "#ifdef DEBUG_UPROBES"; + s.op->newline() << "printk (KERN_WARNING \"uprobe unregister pid %d addr %p\\n\", sup->urp.u.pid, (void*) sup->urp.u.vaddr);"; + s.op->newline() << "#endif"; + s.op->newline() << "unregister_uprobe (& sup->up);"; s.op->newline(-1) << "}"; + s.op->newline(1) << "sup->spec_index = -1;"; s.op->newline() << "handled_p = 1;"; // XXX: Do we need to keep searching the array for other processes, or // can we break just like for the register-new case? @@ -6886,11 +6903,23 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[j];"; s.op->newline() << "struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];"; s.op->newline() << "if (sup->spec_index < 0) continue;"; // free slot - s.op->newline() << "if (sups->return_p) unregister_uretprobe (&sup->urp);"; - s.op->newline() << "else unregister_uprobe (&sup->up);"; + + s.op->newline() << "if (sups->return_p) {"; + s.op->newline(1) << "#ifdef DEBUG_UPROBES"; + s.op->newline() << "printk (KERN_WARNING \"uretprobe unregister2 index %d pid %d addr %p\\n\", sup->spec_index, sup->up.pid, (void*) sup->up.vaddr);"; + s.op->newline() << "#endif"; + s.op->newline() << "unregister_uretprobe (& sup->urp);"; + s.op->newline(-1) << "} else {"; + s.op->newline(1) << "#ifdef DEBUG_UPROBES"; + s.op->newline() << "printk (KERN_WARNING \"uprobe unregister2 index %d pid %d addr %p\\n\", sup->spec_index, sup->urp.u.pid, (void*) sup->urp.u.vaddr);"; + s.op->newline() << "#endif"; + s.op->newline() << "unregister_uprobe (& sup->up);"; + s.op->newline(-1) << "}"; + s.op->newline() << "sup->spec_index = -1;"; - // s.op->newline() << "atomic_add (sdp->u.krp.nmissed, & skipped_count);"; - // s.op->newline() << "atomic_add (sdp->u.krp.kp.nmissed, & skipped_count);"; + + // XXX: uprobe missed counts? + s.op->newline(-1) << "}"; s.op->newline() << "mutex_destroy (& stap_uprobes_lock);"; -- cgit From f02dd36464a34542d5f853d8643cc473af59c5b2 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 2 Sep 2008 17:00:49 -0400 Subject: PR4225: minor uprobe unregistration speedup --- tapsets.cxx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 4cda930f..4fa53a88 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -6790,9 +6790,8 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // unregister old uprobe s.op->newline(-1) << "} else if (!register_p && " << "sup->spec_index == spec_index && " // a u[ret]probe set up for this probe point - << "((sups->return_p && sup->urp.u.pid == tsk->tgid) ||" // dying uretprobe - << "(!sups->return_p && sup->up.pid == tsk->tgid))) {"; // dying uprobe - // XXX: or just check sup->spec_index == spec_index? + << "((sups->return_p && sup->urp.u.pid == tsk->tgid && sup->urp.u.vaddr == relocation + sups->address) ||" // dying uretprobe + << "(!sups->return_p && sup->up.pid == tsk->tgid && sup->up.vaddr == relocation + sups->address))) {"; // dying uprobe s.op->newline() << "if (sups->return_p) {"; s.op->newline(1) << "#ifdef DEBUG_UPROBES"; s.op->newline() << "printk (KERN_WARNING \"uretprobe unregister pid %d addr %p\\n\", sup->up.pid, (void*) sup->up.vaddr);"; @@ -6806,9 +6805,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(-1) << "}"; s.op->newline(1) << "sup->spec_index = -1;"; s.op->newline() << "handled_p = 1;"; - // XXX: Do we need to keep searching the array for other processes, or - // can we break just like for the register-new case? - + s.op->newline() << "break;"; // exit to-free slot search s.op->newline(-1) << "}"; // if/else s.op->newline(-1) << "}"; // stap_uprobes[] loop -- cgit