diff options
author | Frank Ch. Eigler <fche@elastic.org> | 2008-07-22 16:14:02 -0400 |
---|---|---|
committer | Frank Ch. Eigler <fche@elastic.org> | 2008-07-22 16:14:02 -0400 |
commit | 7a24d42223ae98598c99bfb21437a00f13397d6d (patch) | |
tree | 9530b257f13194486b2b33be77dd39038ae92feb | |
parent | 4cdbcfa7fe4a934dc0aabcdd5355d2dbd46821f7 (diff) | |
download | systemtap-steved-7a24d42223ae98598c99bfb21437a00f13397d6d.tar.gz systemtap-steved-7a24d42223ae98598c99bfb21437a00f13397d6d.tar.xz systemtap-steved-7a24d42223ae98598c99bfb21437a00f13397d6d.zip |
PR4225: parse process("path").function/statement probe points
-rw-r--r-- | tapsets.cxx | 282 | ||||
-rw-r--r-- | translate.cxx | 3 |
2 files changed, 186 insertions, 99 deletions
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 <string,dwflpp*> 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<string,dwflpp*>::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 diff --git a/translate.cxx b/translate.cxx index c62ba9fd..5956cba7 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4507,7 +4507,7 @@ emit_symbol_data (systemtap_session& s) unwindsym_dump_context ctx = { s, kallsyms_out, 0, s.unwindsym_modules }; - // XXX: copied from tapsets.cxx, sadly + // XXX: copied from tapsets.cxx dwflpp::, sadly static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug:build"; static char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); @@ -4546,6 +4546,7 @@ emit_symbol_data (systemtap_session& s) // ---- step 2: process any user modules (files) listed + // XXX: see dwflpp::setup_user. static const Dwfl_Callbacks user_callbacks = { NULL, /* dwfl_linux_kernel_find_elf, */ |