From 707bf35ea17c442b797d98d7d2acd8506bfbc65b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 11 May 2009 18:15:31 -0700 Subject: Consolidate dwflpp setup --- tapsets.cxx | 108 +++++++++++++++++++++++------------------------------------- 1 file changed, 41 insertions(+), 67 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 0e419e96..3837ab2b 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -680,7 +680,7 @@ struct dwflpp return t; } - dwflpp(systemtap_session & session) + dwflpp(systemtap_session & session, const string& user_module="") : sess(session), dwfl(NULL), @@ -693,6 +693,10 @@ struct dwflpp cu(NULL), function(NULL) { + if (user_module.empty()) + setup_kernel(); + else + setup_user(user_module); } @@ -763,7 +767,7 @@ struct dwflpp dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL)); } - void setup_user(string module_name, bool debuginfo_needed = true) + void setup_user(const string& module_name, bool debuginfo_needed = true) { if (! sess.module_cache) sess.module_cache = new module_cache (); @@ -2839,6 +2843,19 @@ struct dwarf_builder: public derived_probe_builder map user_dw; dwarf_builder(): kern_dw(0) {} + dwflpp *get_kern_dw(systemtap_session& sess) + { + if (!kern_dw) + kern_dw = new dwflpp(sess); + return kern_dw; + } + + dwflpp *get_user_dw(systemtap_session& sess, const string& module) + { + if (user_dw.find(module) == user_dw.end()) + user_dw[module] = new dwflpp(sess, module); + return user_dw[module]; + } /* NB: not virtual, so can be called from dtor too: */ void dwarf_build_no_more (bool verbose) @@ -4924,51 +4941,24 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) // NB: This uses '/' to distinguish between kernel modules and userspace, // which means that userspace modules won't get any PATH searching. dwflpp* dw; - if (module.find('/') == string::npos) - { - // kernel or kernel module target - if (! db.kern_dw) - { - dw = new dwflpp(s); - try - { - dw->setup_kernel(true); - } - catch (const semantic_error& er) - { - /* ignore and go to the next module */ - delete dw; - continue; - } - db.kern_dw = dw; - } - else - dw = db.kern_dw; - } - else - { - module = find_executable (module); // canonicalize it - - // user-space target; we use one dwflpp instance per module name - // (= program or shared library) - if (db.user_dw.find(module) == db.user_dw.end()) - { - dw = new dwflpp(s); - try - { - dw->setup_user(module); - } - catch (const semantic_error& er) - { - /* ignore and go to the next module */ - delete dw; - continue; - } - db.user_dw[module] = dw; - } - else - dw = db.user_dw[module]; - } + try + { + if (module.find('/') == string::npos) + { + // kernel or kernel module target + dw = db.get_kern_dw(s); + } + else + { + module = find_executable (module); // canonicalize it + dw = db.get_user_dw(s, module); + } + } + catch (const semantic_error& er) + { + /* ignore and go to the next module */ + continue; + } dwarf_cast_query q (*dw, module, *e, lvalue, type, code); dw->query_modules(&q); @@ -5592,13 +5582,7 @@ dwarf_builder::build(systemtap_session & sess, || get_param (parameters, TOK_MODULE, module_name)) { // kernel or kernel module target - if (! kern_dw) - { - kern_dw = new dwflpp(sess); - // XXX: PR 3498, PR 6864 - kern_dw->setup_kernel(true); - } - dw = kern_dw; + dw = get_kern_dw(sess); } else if (get_param (parameters, TOK_PROCESS, module_name)) { @@ -5606,15 +5590,7 @@ dwarf_builder::build(systemtap_session & sess, // user-space target; we use one dwflpp instance per module name // (= program or shared library) - if (user_dw.find(module_name) == user_dw.end()) - { - dw = new dwflpp(sess); - // XXX: PR 3498 - dw->setup_user(module_name); - user_dw[module_name] = dw; - } - else - dw = user_dw[module_name]; + dw = get_user_dw(sess, module_name); } if (sess.verbose > 3) @@ -7886,8 +7862,7 @@ tracepoint_builder::init_dw(systemtap_session& s) if (s.verbose > 2) clog << "Pass 2: using cached " << s.tracequery_path << endl; - dw = new dwflpp(s); - dw->setup_user(s.tracequery_path); + dw = new dwflpp(s, s.tracequery_path); close(fd); return true; } @@ -7912,8 +7887,7 @@ tracepoint_builder::init_dw(systemtap_session& s) << s.tracequery_path << "\"): " << strerror(errno) << endl; } - dw = new dwflpp(s); - dw->setup_user(tracequery_ko); + dw = new dwflpp(s, tracequery_ko); return true; } -- cgit From 440f755a3b886c6cfdca9f523302f1f0938f7fec Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 12 May 2009 19:33:14 -0700 Subject: Move dfwlpp into its own file It's not a terribly clean split, but moving it helps reveals some of the knots that need to be untangled. --- tapsets.cxx | 2535 ++++------------------------------------------------------- 1 file changed, 165 insertions(+), 2370 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 3837ab2b..3aad1730 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -20,17 +20,13 @@ #include "dwarf_wrappers.h" #include "auto_free.h" #include "hash.h" +#include "dwflpp.h" #include #include #include #include #include -#ifdef HAVE_TR1_UNORDERED_MAP -#include -#else -#include -#endif #include #include #include @@ -169,2126 +165,163 @@ common_probe_entryfn_epilogue (translator_output* o, o->newline() << "{"; o->newline(1) << "cycles_t cycles_atend = get_cycles ();"; // NB: we truncate cycles counts to 32 bits. Perhaps it should be - // fewer, if the hardware counter rolls over really quickly. We - // handle 32-bit wraparound here. - o->newline() << "int32_t cycles_elapsed = ((int32_t)cycles_atend > (int32_t)cycles_atstart)"; - o->newline(1) << "? ((int32_t)cycles_atend - (int32_t)cycles_atstart)"; - o->newline() << ": (~(int32_t)0) - (int32_t)cycles_atstart + (int32_t)cycles_atend + 1;"; - o->indent(-1); - - o->newline() << "#ifdef STP_TIMING"; - o->newline() << "if (likely (c->statp)) _stp_stat_add(*c->statp, cycles_elapsed);"; - o->newline() << "#endif"; - - if (overload_processing) - { - o->newline() << "#ifdef STP_OVERLOAD"; - o->newline() << "{"; - // If the cycle count has wrapped (cycles_atend > cycles_base), - // let's go ahead and pretend the interval has been reached. - // This should reset cycles_base and cycles_sum. - o->newline(1) << "cycles_t interval = (cycles_atend > c->cycles_base)"; - o->newline(1) << "? (cycles_atend - c->cycles_base)"; - o->newline() << ": (STP_OVERLOAD_INTERVAL + 1);"; - o->newline(-1) << "c->cycles_sum += cycles_elapsed;"; - - // If we've spent more than STP_OVERLOAD_THRESHOLD cycles in a - // probe during the last STP_OVERLOAD_INTERVAL cycles, the probe - // has overloaded the system and we need to quit. - o->newline() << "if (interval > STP_OVERLOAD_INTERVAL) {"; - o->newline(1) << "if (c->cycles_sum > STP_OVERLOAD_THRESHOLD) {"; - o->newline(1) << "_stp_error (\"probe overhead exceeded threshold\");"; - o->newline() << "atomic_set (&session_state, STAP_SESSION_ERROR);"; - o->newline() << "atomic_inc (&error_count);"; - o->newline(-1) << "}"; - - o->newline() << "c->cycles_base = cycles_atend;"; - o->newline() << "c->cycles_sum = 0;"; - o->newline(-1) << "}"; - o->newline(-1) << "}"; - o->newline() << "#endif"; - } - - o->newline(-1) << "}"; - o->newline() << "#endif"; - - o->newline() << "c->probe_point = 0;"; // vacated - o->newline() << "if (unlikely (c->last_error && c->last_error[0])) {"; - o->newline(1) << "if (c->last_stmt != NULL)"; - o->newline(1) << "_stp_softerror (\"%s near %s\", c->last_error, c->last_stmt);"; - o->newline(-1) << "else"; - o->newline(1) << "_stp_softerror (\"%s\", c->last_error);"; - o->indent(-1); - o->newline() << "atomic_inc (& error_count);"; - o->newline() << "if (atomic_read (& error_count) > MAXERRORS) {"; - o->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; - o->newline() << "_stp_exit ();"; - o->newline(-1) << "}"; - o->newline(-1) << "}"; - o->newline() << "atomic_dec (&c->busy);"; - - o->newline(-1) << "probe_epilogue:"; // context is free - o->indent(1); - - // Check for excessive skip counts. - o->newline() << "if (unlikely (atomic_read (& skipped_count) > MAXSKIPPED)) {"; - o->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; - o->newline() << "_stp_exit ();"; - o->newline(-1) << "}"; - - o->newline() << "#if INTERRUPTIBLE"; - o->newline() << "preempt_enable_no_resched ();"; - o->newline() << "#else"; - o->newline() << "local_irq_restore (flags);"; - o->newline() << "#endif"; -} - - -// ------------------------------------------------------------------------ - -// ------------------------------------------------------------------------ -// Dwarf derived probes. "We apologize for the inconvience." -// ------------------------------------------------------------------------ - -static string TOK_KERNEL("kernel"); -static string TOK_MODULE("module"); -static string TOK_FUNCTION("function"); -static string TOK_INLINE("inline"); -static string TOK_CALL("call"); -static string TOK_RETURN("return"); -static string TOK_MAXACTIVE("maxactive"); -static string TOK_STATEMENT("statement"); -static string TOK_ABSOLUTE("absolute"); -static string TOK_PROCESS("process"); -static string TOK_MARK("mark"); -static string TOK_TRACE("trace"); -static string TOK_LABEL("label"); - -// Can we handle this query with just symbol-table info? -enum dbinfo_reqt -{ - dbr_unknown, - dbr_none, // kernel.statement(NUM).absolute - dbr_need_symtab, // can get by with symbol table if there's no dwarf - dbr_need_dwarf -}; - -enum info_status -{ - info_unknown, - info_present, - info_absent -}; - -struct -func_info -{ - func_info() - : decl_file(NULL), decl_line(-1), addr(0), prologue_end(0), weak(false) - { - memset(&die, 0, sizeof(die)); - } - string name; - char const * decl_file; - int decl_line; - Dwarf_Die die; - Dwarf_Addr addr; - Dwarf_Addr entrypc; - Dwarf_Addr prologue_end; - bool weak; - // Comparison functor for list of functions sorted by address. The - // two versions that take a Dwarf_Addr let us use the STL algorithms - // upper_bound, equal_range et al., but we don't know whether the - // searched-for value will be passed as the first or the second - // argument. - struct Compare - { - bool operator() (const func_info* f1, const func_info* f2) const - { - return f1->addr < f2->addr; - } - // For doing lookups by address. - bool operator() (Dwarf_Addr addr, const func_info* f2) const - { - return addr < f2->addr; - } - bool operator() (const func_info* f1, Dwarf_Addr addr) const - { - return f1->addr < addr; - } - }; -}; - -struct -inline_instance_info -{ - inline_instance_info() - : decl_file(NULL), decl_line(-1) - { - memset(&die, 0, sizeof(die)); - } - string name; - char const * decl_file; - int decl_line; - Dwarf_Addr entrypc; - Dwarf_Die die; -}; - - -struct base_query; // forward decls -struct dwarf_query; -struct dwflpp; -struct symbol_table; - - -struct -module_info -{ - Dwfl_Module* mod; - const char* name; - string elf_path; - Dwarf_Addr addr; - Dwarf_Addr bias; - symbol_table *sym_table; - info_status dwarf_status; // module has dwarf info? - info_status symtab_status; // symbol table cached? - - void get_symtab(dwarf_query *q); - - module_info(const char *name) : - mod(NULL), - name(name), - addr(0), - bias(0), - sym_table(NULL), - dwarf_status(info_unknown), - symtab_status(info_unknown) - {} - - ~module_info(); -}; - -struct -module_cache -{ - map cache; - bool paths_collected; - bool dwarf_collected; - - module_cache() : paths_collected(false), dwarf_collected(false) {} -}; -typedef struct module_cache module_cache_t; - -#ifdef HAVE_TR1_UNORDERED_MAP -typedef tr1::unordered_map cu_function_cache_t; -typedef tr1::unordered_map mod_cu_function_cache_t; // module:cu -> function -> die -#else -struct stringhash { - // __gnu_cxx:: is needed because our own hash.h has an ambiguous hash<> decl too. - size_t operator() (const string& s) const { __gnu_cxx::hash h; return h(s.c_str()); } -}; - -typedef hash_map cu_function_cache_t; -typedef hash_map mod_cu_function_cache_t; // module:cu -> function -> die -#endif - -struct -symbol_table -{ - module_info *mod_info; // associated module - map map_by_name; - vector list_by_addr; - typedef vector::iterator iterator_t; - typedef pair range_t; -#ifdef __powerpc__ - GElf_Word opd_section; -#endif - // add_symbol doesn't leave symbol table in order; call - // symbol_table::sort() when done adding symbols. - void add_symbol(const char *name, bool weak, Dwarf_Addr addr, - Dwarf_Addr *high_addr); - void sort(); - enum info_status read_symbols(FILE *f, const string& path); - enum info_status read_from_elf_file(const string& path); - enum info_status read_from_text_file(const string& path); - enum info_status get_from_elf(); - void prepare_section_rejection(Dwfl_Module *mod); - bool reject_section(GElf_Word section); - void mark_dwarf_redundancies(dwflpp *dw); - void purge_syscall_stubs(); - func_info *lookup_symbol(const string& name); - Dwarf_Addr lookup_symbol_address(const string& name); - func_info *get_func_containing_address(Dwarf_Addr addr); - - symbol_table(module_info *mi) : mod_info(mi) {} - ~symbol_table(); -}; - -static bool null_die(Dwarf_Die *die) -{ - static Dwarf_Die null = { 0 }; - return (!die || !memcmp(die, &null, sizeof(null))); -} - -static int -query_cu (Dwarf_Die * cudie, void * arg); - - -// Helper for dealing with selected portions of libdwfl in a more readable -// fashion, and with specific cleanup / checking / logging options. - -static const char * -dwarf_diename_integrate (Dwarf_Die *die) -{ - Dwarf_Attribute attr_mem; - return dwarf_formstring (dwarf_attr_integrate (die, DW_AT_name, &attr_mem)); -} - -enum line_t { ABSOLUTE, RELATIVE, RANGE, WILDCARD }; - -typedef vector inline_instance_map_t; -typedef vector func_info_map_t; - - -// PR 9941 introduces the need for a predicate - -int dwfl_report_offline_predicate (const char* modname, const char* filename) -{ - if (pending_interrupts) { return -1; } - return 1; -} - -struct dwflpp -{ - systemtap_session & sess; - Dwfl * dwfl; - - // These are "current" values we focus on. - Dwfl_Module * module; - Dwarf * module_dwarf; - Dwarf_Addr module_bias; - module_info * mod_info; - - // These describe the current module's PC address range - Dwarf_Addr module_start; - Dwarf_Addr module_end; - - Dwarf_Die * cu; - Dwarf_Die * function; - - string module_name; - string cu_name; - string function_name; - - string const default_name(char const * in, - char const *) - { - if (in) - return in; - return string(""); - } - - - void get_module_dwarf(bool required = false, bool report = true) - { - 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 "; - if (module_name == "") - msg += "kernel"; - else - msg += string("module ") + module_name; - msg += " debuginfo"; - - int i = dwfl_errno(); - if (i) - msg += string(": ") + dwfl_errmsg (i); - - if (required) - throw semantic_error (msg); - else - cerr << "WARNING: " << msg << "\n"; - } - } - - void focus_on_module(Dwfl_Module * m, module_info * mi) - { - module = m; - mod_info = mi; - if (m) - { - module_name = default_name(dwfl_module_info(module, NULL, - &module_start, &module_end, - NULL, NULL, - NULL, NULL), - "module"); - } - else - { - assert(mi && mi->name && mi->name == TOK_KERNEL); - module_name = mi->name; - module_start = 0; - module_end = 0; - module_bias = mi->bias; - } - - // Reset existing pointers and names - - module_dwarf = NULL; - - cu_name.clear(); - cu = NULL; - - function_name.clear(); - function = NULL; - } - - - void focus_on_cu(Dwarf_Die * c) - { - assert(c); - assert(module); - - cu = c; - cu_name = default_name(dwarf_diename(c), "CU"); - - // Reset existing pointers and names - function_name.clear(); - function = NULL; - } - - - void focus_on_function(Dwarf_Die * f) - { - assert(f); - assert(module); - assert(cu); - - function = f; - function_name = default_name(dwarf_diename(function), - "function"); - } - - - void focus_on_module_containing_global_address(Dwarf_Addr a) - { - assert(dwfl); - cu = NULL; - Dwfl_Module* mod = dwfl_addrmodule(dwfl, a); - if (mod) // address could be wildly out of range - focus_on_module(mod, NULL); - } - - - void query_cu_containing_global_address(Dwarf_Addr a, void *arg) - { - Dwarf_Addr bias; - assert(dwfl); - get_module_dwarf(); - Dwarf_Die* cudie = dwfl_module_addrdie(module, a, &bias); - if (cudie) // address could be wildly out of range - query_cu (cudie, arg); - assert(bias == module_bias); - } - - - void query_cu_containing_module_address(Dwarf_Addr a, void *arg) - { - query_cu_containing_global_address(module_address_to_global(a), arg); - } - - - Dwarf_Addr module_address_to_global(Dwarf_Addr a) - { - assert(dwfl); - assert(module); - get_module_dwarf(); - if (module_name == TOK_KERNEL || dwfl_module_relocations (module) <= 0) - return a; - return a + module_start; - } - - - Dwarf_Addr global_address_to_module(Dwarf_Addr a) - { - assert(module); - get_module_dwarf(); - return a - module_bias; - } - - - bool module_name_matches(string pattern) - { - bool t = (fnmatch(pattern.c_str(), module_name.c_str(), 0) == 0); - if (t && sess.verbose>3) - clog << "pattern '" << pattern << "' " - << "matches " - << "module '" << module_name << "'" << "\n"; - return t; - } - bool name_has_wildcard(string pattern) - { - return (pattern.find('*') != string::npos || - pattern.find('?') != string::npos || - pattern.find('[') != string::npos); - } - bool module_name_final_match(string pattern) - { - // Assume module_name_matches(). Can there be any more matches? - // Not unless the pattern is a wildcard, since module names are - // presumed unique. - return !name_has_wildcard(pattern); - } - - - bool function_name_matches_pattern(string name, string pattern) - { - bool t = (fnmatch(pattern.c_str(), name.c_str(), 0) == 0); - if (t && sess.verbose>3) - clog << "pattern '" << pattern << "' " - << "matches " - << "function '" << name << "'" << "\n"; - return t; - } - bool function_name_matches(string pattern) - { - assert(function); - return function_name_matches_pattern(function_name, pattern); - } - bool function_name_final_match(string pattern) - { - return module_name_final_match (pattern); - } - - - bool cu_name_matches(string pattern) - { - assert(cu); - - // PR 5049: implicit * in front of given path pattern. - // NB: fnmatch() is used without FNM_PATHNAME. - string prefixed_pattern = string("*/") + pattern; - - bool t = (fnmatch(pattern.c_str(), cu_name.c_str(), 0) == 0 || - fnmatch(prefixed_pattern.c_str(), cu_name.c_str(), 0) == 0); - if (t && sess.verbose>3) - clog << "pattern '" << prefixed_pattern << "' " - << "matches " - << "CU '" << cu_name << "'" << "\n"; - return t; - } - - dwflpp(systemtap_session & session, const string& user_module="") - : - sess(session), - dwfl(NULL), - module(NULL), - module_dwarf(NULL), - module_bias(0), - mod_info(NULL), - module_start(0), - module_end(0), - cu(NULL), - function(NULL) - { - if (user_module.empty()) - setup_kernel(); - else - setup_user(user_module); - } - - - // XXX: See also translate.cxx:emit_symbol_data - - void setup_kernel(bool debuginfo_needed = true) - { - if (! sess.module_cache) - sess.module_cache = new module_cache (); - - static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build"; - static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); - static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr ); - - static const Dwfl_Callbacks kernel_callbacks = - { - dwfl_linux_kernel_find_elf, - dwfl_standard_find_debuginfo, - dwfl_offline_section_address, - (char **) & debuginfo_path - }; - - dwfl = dwfl_begin (&kernel_callbacks); - if (!dwfl) - throw semantic_error ("cannot open dwfl"); - dwfl_report_begin (dwfl); - - // We have a problem with -r REVISION vs -r BUILDDIR here. If - // we're running against a fedora/rhel style kernel-debuginfo - // tree, s.kernel_build_tree is not the place where the unstripped - // vmlinux will be installed. Rather, it's over yonder at - // /usr/lib/debug/lib/modules/$REVISION/. It seems that there is - // no way to set the dwfl_callback.debuginfo_path and always - // passs the plain kernel_release here. So instead we have to - // hard-code this magic here. - string elfutils_kernel_path; - if (sess.kernel_build_tree == string("/lib/modules/" + sess.kernel_release + "/build")) - elfutils_kernel_path = sess.kernel_release; - else - elfutils_kernel_path = sess.kernel_build_tree; - - int rc = dwfl_linux_kernel_report_offline (dwfl, - elfutils_kernel_path.c_str(), - &dwfl_report_offline_predicate); - - if (debuginfo_needed) - dwfl_assert (string("missing ") + sess.architecture + - string(" kernel/module debuginfo under '") + - sess.kernel_build_tree + string("'"), - 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(const string& module_name, bool debuginfo_needed = true) - { - if (! sess.module_cache) - sess.module_cache = new module_cache (); - - static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build"; - static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH"); - // NB: kernel_build_tree doesn't enter into this, as it's for - // kernel-side modules only. - static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr); - - static const Dwfl_Callbacks user_callbacks = - { - NULL, /* dwfl_linux_kernel_find_elf, */ - dwfl_standard_find_debuginfo, - dwfl_offline_section_address, - (char **) & debuginfo_path - }; - - dwfl = dwfl_begin (&user_callbacks); - if (!dwfl) - throw semantic_error ("cannot open dwfl"); - dwfl_report_begin (dwfl); - - // XXX: should support buildid-based naming - - Dwfl_Module *mod = dwfl_report_offline (dwfl, - module_name.c_str(), - module_name.c_str(), - -1); - // XXX: save mod! - - if (debuginfo_needed) - dwfl_assert (string("missing process ") + - module_name + - string(" ") + - sess.architecture + - string(" debuginfo"), - mod); - - if (!module) - module = 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)); - } - - - - // ----------------------------------------------------------------- - - void iterate_over_modules(int (* callback)(Dwfl_Module *, void **, - const char *, Dwarf_Addr, - void *), - base_query *data) - { - ptrdiff_t off = 0; - do - { - if (pending_interrupts) return; - off = dwfl_getmodules (dwfl, callback, data, off); - } - while (off > 0); - // Don't complain if we exited dwfl_getmodules early. - // This could be a $target variable error that will be - // reported soon anyway. - // 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. - } - - - // Defined after dwarf_query - void query_modules(base_query *q); - - - // ----------------------------------------------------------------- - - typedef map*> module_cu_cache_t; - module_cu_cache_t module_cu_cache; - - void iterate_over_cus (int (*callback)(Dwarf_Die * die, void * arg), - void * data) - { - get_module_dwarf(false); - Dwarf *dw = module_dwarf; - if (!dw) return; - - vector* v = module_cu_cache[dw]; - if (v == 0) - { - v = new vector; - module_cu_cache[dw] = v; - - Dwarf_Off off = 0; - size_t cuhl; - Dwarf_Off noff; - while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0) - { - if (pending_interrupts) return; - Dwarf_Die die_mem; - Dwarf_Die *die; - die = dwarf_offdie (dw, off + cuhl, &die_mem); - v->push_back (*die); /* copy */ - off = noff; - } - } - - for (unsigned i = 0; i < v->size(); i++) - { - if (pending_interrupts) return; - Dwarf_Die die = v->at(i); - int rc = (*callback)(& die, data); - if (rc != DWARF_CB_OK) break; - } - } - - - // ----------------------------------------------------------------- - - bool func_is_inline() - { - assert (function); - return dwarf_func_inline (function) != 0; - } - - - typedef map*> cu_inl_function_cache_t; - cu_inl_function_cache_t cu_inl_function_cache; - - static int cu_inl_function_caching_callback (Dwarf_Die* func, void *arg) - { - vector* v = static_cast*>(arg); - v->push_back (* func); - return DWARF_CB_OK; - } - - void iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void * arg), - void * data) - { - assert (function); - assert (func_is_inline ()); - - string key = module_name + ":" + cu_name + ":" + function_name; - vector* v = cu_inl_function_cache[key]; - if (v == 0) - { - v = new vector; - cu_inl_function_cache[key] = v; - dwarf_func_inline_instances (function, cu_inl_function_caching_callback, v); - } - - for (unsigned i=0; isize(); i++) - { - if (pending_interrupts) return; - Dwarf_Die die = v->at(i); - int rc = (*callback)(& die, data); - if (rc != DWARF_CB_OK) break; - } - } - - - // ----------------------------------------------------------------- - - /* The global alias cache is used to resolve any DIE found in a - * module that is stubbed out with DW_AT_declaration with a defining - * DIE found in a different module. The current assumption is that - * this only applies to structures and unions, which have a global - * namespace (it deliberately only traverses program scope), so this - * cache is indexed by name. If other declaration lookups were - * added to it, it would have to be indexed by name and tag - */ - mod_cu_function_cache_t global_alias_cache; - static int global_alias_caching_callback(Dwarf_Die *die, void *arg) - { - cu_function_cache_t *cache = static_cast(arg); - const char *name = dwarf_diename(die); - - if (!name) - return DWARF_CB_OK; - - string structure_name = name; - - if (!dwarf_hasattr(die, DW_AT_declaration) && - cache->find(structure_name) == cache->end()) - (*cache)[structure_name] = *die; - - return DWARF_CB_OK; - } - - Dwarf_Die *declaration_resolve(const char *name) - { - if (!name) - return NULL; - - string key = module_name + ":" + cu_name; - cu_function_cache_t *v = global_alias_cache[key]; - if (v == 0) // need to build the cache, just once per encountered module/cu - { - v = new cu_function_cache_t; - global_alias_cache[key] = v; - iterate_over_globals(global_alias_caching_callback, v); - if (sess.verbose > 4) - clog << "global alias cache " << key << " size " << v->size() << endl; - } - - // XXX: it may be desirable to search other modules' declarations - // too, in case a module/shared-library processes a - // forward-declared pointer type only, where the actual definition - // may only be in vmlinux or the application. - - // XXX: it is probably desirable to search other CU's declarations - // in the same module. - - if (v->find(name) == v->end()) - return NULL; - - return & ((*v)[name]); - } - - mod_cu_function_cache_t cu_function_cache; - - static int cu_function_caching_callback (Dwarf_Die* func, void *arg) - { - cu_function_cache_t* v = static_cast(arg); - const char *name = dwarf_diename(func); - if (!name) - return DWARF_CB_OK; - - string function_name = name; - (*v)[function_name] = * func; - return DWARF_CB_OK; - } - - int iterate_over_functions (int (* callback)(Dwarf_Die * func, base_query * q), - base_query * q, const string& function, - bool has_statement_num=false); - int iterate_over_globals (int (* callback)(Dwarf_Die *, void *), - void * data); - - bool has_single_line_record (dwarf_query * q, char const * srcfile, int lineno); - - void iterate_over_srcfile_lines (char const * srcfile, - int lines[2], - bool need_single_match, - enum line_t line_type, - void (* callback) (const dwarf_line_t& line, - void * arg), - void *data) - { - Dwarf_Line **srcsp = NULL; - size_t nsrcs = 0; - dwarf_query * q = static_cast(data); - int lineno = lines[0]; - auto_free_ref free_srcsp(srcsp); - - get_module_dwarf(); - - if (line_type == RELATIVE) - { - Dwarf_Addr addr; - Dwarf_Line *line; - int line_number; - - dwarf_assert ("dwarf_entrypc", dwarf_entrypc (this->function, &addr)); - line = dwarf_getsrc_die (this->cu, addr); - dwarf_assert ("dwarf_getsrc_die", line == NULL); - dwarf_assert ("dwarf_lineno", dwarf_lineno (line, &line_number)); - lineno += line_number; - } - else if (line_type == WILDCARD) - function_line (&lineno); - - for (int l = lineno; ; l = l + 1) - { - set lines_probed; - pair::iterator,bool> line_probed; - dwarf_assert ("dwarf_getsrc_file", - dwarf_getsrc_file (module_dwarf, - srcfile, l, 0, - &srcsp, &nsrcs)); - if (line_type == WILDCARD || line_type == RANGE) - { - Dwarf_Addr line_addr; - dwarf_lineno (srcsp [0], &lineno); - line_probed = lines_probed.insert(lineno); - if (lineno != l || line_probed.second == false || nsrcs > 1) - continue; - dwarf_lineaddr (srcsp [0], &line_addr); - if (dwarf_haspc (function, line_addr) != 1) - break; - } - - // NB: Formerly, we used to filter, because: - - // dwarf_getsrc_file gets one *near hits* for line numbers, not - // exact matches. For example, an existing file but a nonexistent - // line number will be rounded up to the next definition in that - // file. This may be similar to the GDB breakpoint algorithm, but - // we don't want to be so fuzzy in systemtap land. So we filter. - - // But we now see the error of our ways, and skip this filtering. - - // XXX: the code also fails to match e.g. inline function - // definitions when the srcfile is a header file rather than the - // CU name. - - size_t remaining_nsrcs = nsrcs; - - if (need_single_match && remaining_nsrcs > 1) - { - // We wanted a single line record (a unique address for the - // line) and we got a bunch of line records. We're going to - // skip this probe (throw an exception) but before we throw - // we're going to look around a bit to see if there's a low or - // high line number nearby which *doesn't* have this problem, - // so we can give the user some advice. - - int lo_try = -1; - int hi_try = -1; - for (size_t i = 1; i < 6; ++i) - { - if (lo_try == -1 && has_single_line_record(q, srcfile, lineno - i)) - lo_try = lineno - i; - - if (hi_try == -1 && has_single_line_record(q, srcfile, lineno + i)) - hi_try = lineno + i; - } - - stringstream advice; - advice << "multiple addresses for " << srcfile << ":" << lineno; - if (lo_try > 0 || hi_try > 0) - { - advice << " (try "; - if (lo_try > 0) - advice << srcfile << ":" << lo_try; - if (lo_try > 0 && hi_try > 0) - advice << " or "; - if (hi_try > 0) - advice << srcfile << ":" << hi_try; - advice << ")"; - } - throw semantic_error (advice.str()); - } - - for (size_t i = 0; i < nsrcs; ++i) - { - if (pending_interrupts) return; - if (srcsp [i]) // skip over mismatched lines - callback (dwarf_line_t(srcsp[i]), data); - } - - if (line_type == ABSOLUTE || line_type == RELATIVE) - break; - else if (line_type == RANGE && l == lines[1]) - break; - } - } - - void - iterate_over_labels (Dwarf_Die *begin_die, - void *data, - void (* callback)(const string &, - const char *, - int, - Dwarf_Die *, - Dwarf_Addr, - dwarf_query *)); - - void collect_srcfiles_matching (string const & pattern, - set & filtered_srcfiles) - { - assert (module); - assert (cu); - - 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 || - fnmatch (prefixed_pattern.c_str(), fname, 0) == 0) - { - filtered_srcfiles.insert (fname); - if (sess.verbose>2) - clog << "selected source file '" << fname << "'\n"; - } - } - } - } - - void resolve_prologue_endings (func_info_map_t & funcs) - { - // This heuristic attempts to pick the first address that has a - // source line distinct from the function declaration's. In a - // perfect world, this would be the first statement *past* the - // prologue. - - assert(module); - assert(cu); - - size_t nlines = 0; - Dwarf_Lines *lines = NULL; - - /* trouble cases: - malloc do_symlink in init/initramfs.c tail-recursive/tiny then no-prologue - sys_get?id in kernel/timer.c no-prologue - sys_exit_group tail-recursive - {do_,}sys_open extra-long-prologue (gcc 3.4) - cpu_to_logical_apicid NULL-decl_file - */ - - // Fetch all srcline records, sorted by address. - dwarf_assert ("dwarf_getsrclines", - dwarf_getsrclines(cu, &lines, &nlines)); - // XXX: free lines[] later, but how? - - for(func_info_map_t::iterator it = funcs.begin(); it != funcs.end(); it++) - { -#if 0 /* someday */ - Dwarf_Addr* bkpts = 0; - int n = dwarf_entry_breakpoints (& it->die, & bkpts); - // ... - free (bkpts); -#endif - - Dwarf_Addr entrypc = it->entrypc; - Dwarf_Addr highpc; // NB: highpc is exclusive: [entrypc,highpc) - dwfl_assert ("dwarf_highpc", dwarf_highpc (& it->die, - & highpc)); - - if (it->decl_file == 0) it->decl_file = ""; - - unsigned entrypc_srcline_idx = 0; - dwarf_line_t entrypc_srcline; - // open-code binary search for exact match - { - unsigned l = 0, h = nlines; - while (l < h) - { - entrypc_srcline_idx = (l + h) / 2; - const dwarf_line_t lr(dwarf_onesrcline(lines, - entrypc_srcline_idx)); - Dwarf_Addr addr = lr.addr(); - if (addr == entrypc) { entrypc_srcline = lr; break; } - else if (l + 1 == h) { break; } // ran off bottom of tree - else if (addr < entrypc) { l = entrypc_srcline_idx; } - else { h = entrypc_srcline_idx; } - } - } - if (!entrypc_srcline) - { - if (sess.verbose > 2) - clog << "missing entrypc dwarf line record for function '" - << it->name << "'\n"; - // This is probably an inlined function. We'll end up using - // its lowpc as a probe address. - continue; - } - - if (sess.verbose>2) - clog << "prologue searching function '" << it->name << "'" - << " 0x" << hex << entrypc << "-0x" << highpc << dec - << "@" << it->decl_file << ":" << it->decl_line - << "\n"; - - // Now we go searching for the first line record that has a - // file/line different from the one in the declaration. - // Normally, this will be the next one. BUT: - // - // We may have to skip a few because some old compilers plop - // in dummy line records for longer prologues. If we go too - // far (addr >= highpc), we take the previous one. Or, it may - // be the first one, if the function had no prologue, and thus - // the entrypc maps to a statement in the body rather than the - // declaration. - - unsigned postprologue_srcline_idx = entrypc_srcline_idx; - bool ranoff_end = false; - while (postprologue_srcline_idx < nlines) - { - dwarf_line_t lr(dwarf_onesrcline(lines, postprologue_srcline_idx)); - Dwarf_Addr postprologue_addr = lr.addr(); - const char* postprologue_file = lr.linesrc(); - int postprologue_lineno = lr.lineno(); - - if (sess.verbose>2) - clog << "checking line record 0x" << hex << postprologue_addr << dec - << "@" << postprologue_file << ":" << postprologue_lineno << "\n"; - - if (postprologue_addr >= highpc) - { - ranoff_end = true; - postprologue_srcline_idx --; - continue; - } - if (ranoff_end || - (strcmp (postprologue_file, it->decl_file) || // We have a winner! - (postprologue_lineno != it->decl_line))) - { - it->prologue_end = postprologue_addr; - - if (sess.verbose>2) - { - clog << "prologue found function '" << it->name << "'"; - // Add a little classification datum - if (postprologue_srcline_idx == entrypc_srcline_idx) clog << " (naked)"; - if (ranoff_end) clog << " (tail-call?)"; - clog << " = 0x" << hex << postprologue_addr << dec << "\n"; - } - - break; - } - - // Let's try the next srcline. - postprologue_srcline_idx ++; - } // loop over srclines - - // if (strlen(it->decl_file) == 0) it->decl_file = NULL; - - } // loop over functions - - // XXX: how to free lines? - } - - - bool function_entrypc (Dwarf_Addr * addr) - { - assert (function); - return (dwarf_entrypc (function, addr) == 0); - // XXX: see also _lowpc ? - } - - - bool die_entrypc (Dwarf_Die * die, Dwarf_Addr * addr) - { - int rc = 0; - string lookup_method; - - * addr = 0; - - lookup_method = "dwarf_entrypc"; - rc = dwarf_entrypc (die, addr); - - if (rc) - { - lookup_method = "dwarf_lowpc"; - rc = dwarf_lowpc (die, addr); - } - - if (rc) - { - lookup_method = "dwarf_ranges"; - - Dwarf_Addr base; - Dwarf_Addr begin; - Dwarf_Addr end; - ptrdiff_t offset = dwarf_ranges (die, 0, &base, &begin, &end); - if (offset < 0) rc = -1; - else if (offset > 0) - { - * addr = begin; - rc = 0; - - // Now we need to check that there are no more ranges - // associated with this function, which could conceivably - // happen if a function is inlined, then pieces of it are - // split amongst different conditional branches. It's not - // obvious which of them to favour. As a heuristic, we - // pick the beginning of the first range, and ignore the - // others (but with a warning). - - unsigned extra = 0; - while ((offset = dwarf_ranges (die, offset, &base, &begin, &end)) > 0) - extra ++; - if (extra) - lookup_method += ", ignored " + lex_cast(extra) + " more"; - } - } - - if (sess.verbose > 2) - clog << "entry-pc lookup (" << lookup_method << ") = 0x" << hex << *addr << dec - << " (rc " << rc << ")" - << endl; - return (rc == 0); - } - - void function_die (Dwarf_Die *d) - { - assert (function); - *d = *function; - } - - void function_file (char const ** c) - { - assert (function); - assert (c); - *c = dwarf_decl_file (function); - } - - void function_line (int *linep) - { - assert (function); - dwarf_decl_line (function, linep); - } - - bool die_has_pc (Dwarf_Die & die, Dwarf_Addr pc) - { - int res = dwarf_haspc (&die, pc); - // dwarf_ranges will return -1 if a function die has no DW_AT_ranges - // if (res == -1) - // dwarf_assert ("dwarf_haspc", res); - return res == 1; - } - - - static void loc2c_error (void *, const char *fmt, ...) - { - const char *msg = "?"; - char *tmp = NULL; - int rc; - va_list ap; - va_start (ap, fmt); - rc = vasprintf (& tmp, fmt, ap); - if (rc < 0) - msg = "?"; - else - msg = tmp; - va_end (ap); - throw semantic_error (msg); - } - - // This function generates code used for addressing computations of - // target variables. - void emit_address (struct obstack *pool, Dwarf_Addr address) - { - #if 0 - // The easy but incorrect way is to just print a hard-wired - // constant. - obstack_printf (pool, "%#" PRIx64 "UL", address); - #endif - - // Turn this address into a section-relative offset if it should be one. - // We emit a comment approximating the variable+offset expression that - // relocatable module probing code will need to have. - Dwfl_Module *mod = dwfl_addrmodule (dwfl, address); - dwfl_assert ("dwfl_addrmodule", mod); - const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, - NULL, NULL, NULL, NULL); - int n = dwfl_module_relocations (mod); - dwfl_assert ("dwfl_module_relocations", n >= 0); - Dwarf_Addr reloc_address = address; - int i = dwfl_module_relocate_address (mod, &reloc_address); - dwfl_assert ("dwfl_module_relocate_address", i >= 0); - dwfl_assert ("dwfl_module_info", modname); - const char *secname = dwfl_module_relocation_info (mod, i, NULL); - - if (sess.verbose > 2) - { - clog << "emit dwarf addr 0x" << hex << address << dec - << " => module " << modname - << " section " << (secname ?: "null") - << " relocaddr 0x" << hex << reloc_address << dec - << endl; - } - - if (n > 0 && !(n == 1 && secname == NULL)) - { - dwfl_assert ("dwfl_module_relocation_info", secname); - if (n > 1 || secname[0] != '\0') - { - // This gives us the module name, and section name within the - // module, for a kernel module (or other ET_REL module object). - obstack_printf (pool, "({ static unsigned long addr = 0; "); - obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ", - modname, secname, reloc_address); - obstack_printf (pool, "addr; })"); - } - else if (n == 1 && module_name == TOK_KERNEL && secname[0] == '\0') - { - // elfutils' way of telling us that this is a relocatable kernel address, which we - // need to treat the same way here as dwarf_query::add_probe_point does: _stext. - address -= sess.sym_stext; - secname = "_stext"; - obstack_printf (pool, "({ static unsigned long addr = 0; "); - obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ", - modname, secname, address); // PR10000 NB: not reloc_address - obstack_printf (pool, "addr; })"); - } - else - { - throw semantic_error ("cannot relocate user-space dso (?) address"); -#if 0 - // This would happen for a Dwfl_Module that's a user-level DSO. - obstack_printf (pool, " /* %s+%#" PRIx64 " */", - modname, address); -#endif - } - } - else - obstack_printf (pool, "%#" PRIx64 "UL", address); // assume as constant - } - - static void loc2c_emit_address (void *arg, struct obstack *pool, - Dwarf_Addr address) - { - dwflpp *dwfl = (dwflpp *) arg; - dwfl->emit_address (pool, address); - } - - void print_locals(Dwarf_Die *die, ostream &o) - { - // Try to get the first child of die. - Dwarf_Die child; - if (dwarf_child (die, &child) == 0) - { - do - { - const char *name; - // Output each sibling's name (that is a variable or - // parameter) to 'o'. - switch (dwarf_tag (&child)) - { - case DW_TAG_variable: - case DW_TAG_formal_parameter: - name = dwarf_diename (&child); - if (name) - o << " " << name; - break; - default: - break; - } - } - while (dwarf_siblingof (&child, &child) == 0); - } - } - - Dwarf_Attribute * - find_variable_and_frame_base (Dwarf_Die *scope_die, - Dwarf_Addr pc, - string const & local, - const target_symbol *e, - Dwarf_Die *vardie, - Dwarf_Attribute *fb_attr_mem) - { - Dwarf_Die *scopes; - int nscopes = 0; - Dwarf_Attribute *fb_attr = NULL; - - assert (cu); - - nscopes = dwarf_getscopes (cu, pc, &scopes); - int sidx; - // if pc and scope_die are disjoint then we need dwarf_getscopes_die - for (sidx = 0; sidx < nscopes; sidx++) - if (scopes[sidx].addr == scope_die->addr) - break; - if (sidx == nscopes) - nscopes = dwarf_getscopes_die (scope_die, &scopes); - - if (nscopes <= 0) - { - throw semantic_error ("unable to find any scopes containing " - + lex_cast_hex(pc) - + ((scope_die == NULL) ? "" - : (string (" in ") - + (dwarf_diename(scope_die) ?: "") - + "(" + (dwarf_diename(cu) ?: "") - + ")")) - + " while searching for local '" + local + "'", - e->tok); - } - - int declaring_scope = dwarf_getscopevar (scopes, nscopes, - local.c_str(), - 0, NULL, 0, 0, - vardie); - if (declaring_scope < 0) - { - stringstream alternatives; - print_locals (scopes, alternatives); - throw semantic_error ("unable to find local '" + local + "'" - + " near pc " + lex_cast_hex(pc) - + ((scope_die == NULL) ? "" - : (string (" in ") - + (dwarf_diename(scope_die) ?: "") - + "(" + (dwarf_diename(cu) ?: "") - + ")")) - + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")), - e->tok); - } - - for (int inner = 0; inner < nscopes; ++inner) - { - switch (dwarf_tag (&scopes[inner])) - { - default: - continue; - case DW_TAG_subprogram: - case DW_TAG_entry_point: - case DW_TAG_inlined_subroutine: /* XXX */ - if (inner >= declaring_scope) - fb_attr = dwarf_attr_integrate (&scopes[inner], - DW_AT_frame_base, - fb_attr_mem); - break; - } - } - return fb_attr; - } - - - struct location * - translate_location(struct obstack *pool, - Dwarf_Attribute *attr, Dwarf_Addr pc, - Dwarf_Attribute *fb_attr, - struct location **tail, - const target_symbol *e) - { - Dwarf_Op *expr; - size_t len; - - /* PR9768: formerly, we added pc+module_bias here. However, that bias value - is not present in the pc value by the time we get it, so adding it would - result in false negatives of variable reachibility. In other instances - further below, the c_translate_FOO functions, the module_bias value used - to be passed in, but instead should now be zero for the same reason. */ - - switch (dwarf_getlocation_addr (attr, pc /*+ module_bias*/, &expr, &len, 1)) - { - case 1: /* Should always happen. */ - if (len > 0) - break; - /* Fall through. */ - - case 0: /* Shouldn't happen. */ - throw semantic_error ("not accessible at this address", e->tok); - - default: /* Shouldn't happen. */ - case -1: - throw semantic_error (string ("dwarf_getlocation_addr failed") + - string (dwarf_errmsg (-1)), - e->tok); - } - - return c_translate_location (pool, &loc2c_error, this, - &loc2c_emit_address, - 1, 0 /* PR9768 */, - pc, expr, len, tail, fb_attr); - } - - void - print_members(Dwarf_Die *vardie, ostream &o) - { - const int typetag = dwarf_tag (vardie); - - if (typetag != DW_TAG_structure_type && typetag != DW_TAG_union_type) - { - o << " Error: " - << (dwarf_diename_integrate (vardie) ?: "") - << " isn't a struct/union"; - return; - } - - // Try to get the first child of vardie. - Dwarf_Die die_mem; - Dwarf_Die *die = &die_mem; - switch (dwarf_child (vardie, die)) - { - case 1: // No children. - o << ((typetag == DW_TAG_union_type) ? " union " : " struct ") - << (dwarf_diename_integrate (die) ?: "") - << " is empty"; - break; - - case -1: // Error. - default: // Shouldn't happen. - o << ((typetag == DW_TAG_union_type) ? " union " : " struct ") - << (dwarf_diename_integrate (die) ?: "") - << ": " << dwarf_errmsg (-1); - break; - - case 0: // Success. - break; - } - - // Output each sibling's name to 'o'. - while (dwarf_tag (die) == DW_TAG_member) - { - const char *member = dwarf_diename_integrate (die) ; - - if ( member != NULL ) - o << " " << member; - else - { - Dwarf_Die temp_die = *die; - Dwarf_Attribute temp_attr ; - - if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr)) - { - clog << "\n Error in obtaining type attribute for " - << (dwarf_diename(&temp_die)?:""); - return; - } - - if (!dwarf_formref_die (&temp_attr, &temp_die)) - { - clog << "\n Error in decoding type attribute for " - << (dwarf_diename(&temp_die)?:""); - return; - } - - print_members(&temp_die,o); - } - - if (dwarf_siblingof (die, &die_mem) != 0) - break; - } - } - - bool - find_struct_member(const string& member, - Dwarf_Die *parentdie, - const target_symbol *e, - Dwarf_Die *memberdie, - vector& locs) - { - Dwarf_Attribute attr; - Dwarf_Die die = *parentdie; - - switch (dwarf_child (&die, &die)) - { - case 0: /* First child found. */ - break; - case 1: /* No children. */ - return false; - case -1: /* Error. */ - default: /* Shouldn't happen */ - throw semantic_error (string (dwarf_tag(&die) == DW_TAG_union_type ? "union" : "struct") - + string (dwarf_diename_integrate (&die) ?: "") - + string (dwarf_errmsg (-1)), - e->tok); - } - - do - { - if (dwarf_tag(&die) != DW_TAG_member) - continue; - - const char *name = dwarf_diename_integrate(&die); - if (name == NULL) - { - // need to recurse for anonymous structs/unions - Dwarf_Die subdie; - - if (!dwarf_attr_integrate (&die, DW_AT_type, &attr) || - !dwarf_formref_die (&attr, &subdie)) - continue; - - if (find_struct_member(member, &subdie, e, memberdie, locs)) - goto success; - } - else if (name == member) - { - *memberdie = die; - goto success; - } - } - while (dwarf_siblingof (&die, &die) == 0); - - return false; - -success: - /* As we unwind the recursion, we need to build the chain of - * locations that got to the final answer. */ - if (dwarf_attr_integrate (&die, DW_AT_data_member_location, &attr)) - locs.insert(locs.begin(), attr); - - /* Union members don't usually have a location, - * but just use the containing union's location. */ - else if (dwarf_tag(parentdie) != DW_TAG_union_type) - throw semantic_error ("no location for field '" + member - + "': " + string(dwarf_errmsg (-1)), - e->tok); - - return true; - } - - Dwarf_Die * - translate_components(struct obstack *pool, - struct location **tail, - Dwarf_Addr pc, - const target_symbol *e, - Dwarf_Die *vardie, - Dwarf_Die *die_mem, - Dwarf_Attribute *attr_mem) - { - Dwarf_Die *die = NULL; - - unsigned i = 0; - - if (vardie) - *die_mem = *vardie; - - if (e->components.empty()) - return die_mem; - - while (i < e->components.size()) - { - /* XXX: This would be desirable, but we don't get the target_symbol token, - and printing that gives us the file:line number too early anyway. */ -#if 0 - // Emit a marker to note which field is being access-attempted, to give - // better error messages if deref() fails. - string piece = string(...target_symbol token...) + string ("#") + stringify(components[i].second); - obstack_printf (pool, "c->last_stmt = %s;", lex_cast_qstring(piece).c_str()); -#endif - - die = die ? dwarf_formref_die (attr_mem, die_mem) : die_mem; - const int typetag = dwarf_tag (die); - switch (typetag) - { - case DW_TAG_typedef: - case DW_TAG_const_type: - case DW_TAG_volatile_type: - /* Just iterate on the referent type. */ - break; - - case DW_TAG_pointer_type: - if (e->components[i].first == target_symbol::comp_literal_array_index) - throw semantic_error ("cannot index pointer", e->tok); - // XXX: of course, we should support this the same way C does, - // by explicit pointer arithmetic etc. PR4166. - - c_translate_pointer (pool, 1, 0 /* PR9768*/, die, tail); - break; - - case DW_TAG_array_type: - if (e->components[i].first == target_symbol::comp_literal_array_index) - { - c_translate_array (pool, 1, 0 /* PR9768 */, die, tail, - NULL, lex_cast(e->components[i].second)); - ++i; - } - else - throw semantic_error("bad field '" - + e->components[i].second - + "' for array type", - e->tok); - break; - - case DW_TAG_structure_type: - case DW_TAG_union_type: - if (dwarf_hasattr(die, DW_AT_declaration)) - { - Dwarf_Die *tmpdie = dwflpp::declaration_resolve(dwarf_diename(die)); - if (tmpdie == NULL) - throw semantic_error ("unresolved struct " - + string (dwarf_diename_integrate (die) ?: ""), - e->tok); - *die_mem = *tmpdie; - } - - { - vector locs; - if (!find_struct_member(e->components[i].second, die, e, die, locs)) - { - string alternatives; - stringstream members; - print_members(die, members); - if (members.str().size() != 0) - alternatives = " (alternatives:" + members.str(); - throw semantic_error("unable to find member '" + - e->components[i].second + "' for struct " - + string(dwarf_diename_integrate(die) ?: "") - + alternatives, - e->tok); - } - - for (unsigned j = 0; j < locs.size(); ++j) - translate_location (pool, &locs[j], pc, NULL, tail, e); - } - - ++i; - break; - - case DW_TAG_enumeration_type: - throw semantic_error ("field '" - + e->components[i].second - + "' vs. enum type " - + string(dwarf_diename_integrate (die) ?: ""), - e->tok); - break; - case DW_TAG_base_type: - throw semantic_error ("field '" - + e->components[i].second - + "' vs. base type " - + string(dwarf_diename_integrate (die) ?: ""), - e->tok); - break; - case -1: - throw semantic_error ("cannot find type: " + string(dwarf_errmsg (-1)), - e->tok); - break; - - default: - throw semantic_error (string(dwarf_diename_integrate (die) ?: "") - + ": unexpected type tag " - + lex_cast(dwarf_tag (die)), - e->tok); - break; - } - - /* Now iterate on the type in DIE's attribute. */ - if (dwarf_attr_integrate (die, DW_AT_type, attr_mem) == NULL) - throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1)), e->tok); - } - return die; - } - - - Dwarf_Die * - resolve_unqualified_inner_typedie (Dwarf_Die *typedie_mem, - Dwarf_Attribute *attr_mem, - const target_symbol *e) - { - Dwarf_Die *typedie; - int typetag = 0; - while (1) - { - typedie = dwarf_formref_die (attr_mem, typedie_mem); - if (typedie == NULL) - throw semantic_error ("cannot get type: " + string(dwarf_errmsg (-1)), e->tok); - typetag = dwarf_tag (typedie); - if (typetag != DW_TAG_typedef && - typetag != DW_TAG_const_type && - typetag != DW_TAG_volatile_type) - break; - if (dwarf_attr_integrate (typedie, DW_AT_type, attr_mem) == NULL) - throw semantic_error ("cannot get type of pointee: " + string(dwarf_errmsg (-1)), e->tok); - } - return typedie; - } - - - void - translate_final_fetch_or_store (struct obstack *pool, - struct location **tail, - Dwarf_Addr module_bias, - Dwarf_Die *die, - Dwarf_Attribute *attr_mem, - bool lvalue, - const target_symbol *e, - string &, - string &, - exp_type & ty) - { - /* First boil away any qualifiers associated with the type DIE of - the final location to be accessed. */ - - Dwarf_Die typedie_mem; - Dwarf_Die *typedie; - int typetag; - char const *dname; - string diestr; - - typedie = resolve_unqualified_inner_typedie (&typedie_mem, attr_mem, e); - typetag = dwarf_tag (typedie); - - /* Then switch behavior depending on the type of fetch/store we - want, and the type and pointer-ness of the final location. */ - - switch (typetag) - { - default: - dname = dwarf_diename(die); - diestr = (dname != NULL) ? dname : ""; - throw semantic_error ("unsupported type tag " - + lex_cast(typetag) - + " for " + diestr, e->tok); - break; - - case DW_TAG_structure_type: - case DW_TAG_union_type: - dname = dwarf_diename(die); - diestr = (dname != NULL) ? dname : ""; - throw semantic_error ("struct/union '" + diestr - + "' is being accessed instead of a member of the struct/union", e->tok); - break; - - 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 = (Dwarf_Word) -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, e->tok); - } - - 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, e->tok); - } - } - - ty = pe_long; - if (lvalue) - c_translate_store (pool, 1, 0 /* PR9768 */, die, typedie, tail, - "THIS->value"); - else - c_translate_fetch (pool, 1, 0 /* PR9768 */, die, typedie, tail, - "THIS->__retvalue"); - break; - - case DW_TAG_array_type: - case DW_TAG_pointer_type: - - { - Dwarf_Die pointee_typedie_mem; - Dwarf_Die *pointee_typedie; - Dwarf_Word pointee_encoding; - Dwarf_Word pointee_byte_size = 0; - - pointee_typedie = resolve_unqualified_inner_typedie (&pointee_typedie_mem, attr_mem, e); - - if (dwarf_attr_integrate (pointee_typedie, DW_AT_byte_size, attr_mem)) - dwarf_formudata (attr_mem, &pointee_byte_size); - - dwarf_formudata (dwarf_attr_integrate (pointee_typedie, DW_AT_encoding, attr_mem), - &pointee_encoding); - - if (lvalue) - { - ty = pe_long; - if (typetag == DW_TAG_array_type) - throw semantic_error ("cannot write to array address", e->tok); - assert (typetag == DW_TAG_pointer_type); - c_translate_pointer_store (pool, 1, 0 /* PR9768 */, typedie, tail, - "THIS->value"); - } - else - { - // We have the pointer: cast it to an integral type via &(*(...)) - - // NB: per bug #1187, at one point char*-like types were - // automagically converted here to systemtap string values. - // For several reasons, this was taken back out, leaving - // pointer-to-string "conversion" (copying) to tapset functions. - - ty = pe_long; - if (typetag == DW_TAG_array_type) - c_translate_array (pool, 1, 0 /* PR9768 */, typedie, tail, NULL, 0); - else - c_translate_pointer (pool, 1, 0 /* PR9768 */, typedie, tail); - c_translate_addressof (pool, 1, 0 /* PR9768 */, NULL, pointee_typedie, tail, - "THIS->__retvalue"); - } - } - break; - } - } + // fewer, if the hardware counter rolls over really quickly. We + // handle 32-bit wraparound here. + o->newline() << "int32_t cycles_elapsed = ((int32_t)cycles_atend > (int32_t)cycles_atstart)"; + o->newline(1) << "? ((int32_t)cycles_atend - (int32_t)cycles_atstart)"; + o->newline() << ": (~(int32_t)0) - (int32_t)cycles_atstart + (int32_t)cycles_atend + 1;"; + o->indent(-1); - string - express_as_string (string prelude, - string postlude, - struct location *head) - { - size_t bufsz = 1024; - char *buf = static_cast(malloc(bufsz)); - assert(buf); - - FILE *memstream = open_memstream (&buf, &bufsz); - assert(memstream); - - fprintf(memstream, "{\n"); - fprintf(memstream, "%s", prelude.c_str()); - bool deref = c_emit_location (memstream, head, 1); - fprintf(memstream, "%s", postlude.c_str()); - fprintf(memstream, " goto out;\n"); - - // dummy use of deref_fault label, to disable warning if deref() not used - fprintf(memstream, "if (0) goto deref_fault;\n"); - - // XXX: deref flag not reliable; emit fault label unconditionally - (void) deref; - fprintf(memstream, - "deref_fault:\n" - " goto out;\n"); - fprintf(memstream, "}\n"); - - fclose (memstream); - string result(buf); - free (buf); - return result; - } + o->newline() << "#ifdef STP_TIMING"; + o->newline() << "if (likely (c->statp)) _stp_stat_add(*c->statp, cycles_elapsed);"; + o->newline() << "#endif"; - string - literal_stmt_for_local (Dwarf_Die *scope_die, - Dwarf_Addr pc, - string const & local, - const target_symbol *e, - bool lvalue, - exp_type & ty) - { - Dwarf_Die vardie; - Dwarf_Attribute fb_attr_mem, *fb_attr = NULL; + if (overload_processing) + { + o->newline() << "#ifdef STP_OVERLOAD"; + o->newline() << "{"; + // If the cycle count has wrapped (cycles_atend > cycles_base), + // let's go ahead and pretend the interval has been reached. + // This should reset cycles_base and cycles_sum. + o->newline(1) << "cycles_t interval = (cycles_atend > c->cycles_base)"; + o->newline(1) << "? (cycles_atend - c->cycles_base)"; + o->newline() << ": (STP_OVERLOAD_INTERVAL + 1);"; + o->newline(-1) << "c->cycles_sum += cycles_elapsed;"; - fb_attr = find_variable_and_frame_base (scope_die, pc, local, e, - &vardie, &fb_attr_mem); + // If we've spent more than STP_OVERLOAD_THRESHOLD cycles in a + // probe during the last STP_OVERLOAD_INTERVAL cycles, the probe + // has overloaded the system and we need to quit. + o->newline() << "if (interval > STP_OVERLOAD_INTERVAL) {"; + o->newline(1) << "if (c->cycles_sum > STP_OVERLOAD_THRESHOLD) {"; + o->newline(1) << "_stp_error (\"probe overhead exceeded threshold\");"; + o->newline() << "atomic_set (&session_state, STAP_SESSION_ERROR);"; + o->newline() << "atomic_inc (&error_count);"; + o->newline(-1) << "}"; - if (sess.verbose>2) - clog << "finding location for local '" << local - << "' near address 0x" << hex << pc - << ", module bias 0x" << module_bias << dec - << "\n"; + o->newline() << "c->cycles_base = cycles_atend;"; + o->newline() << "c->cycles_sum = 0;"; + o->newline(-1) << "}"; + o->newline(-1) << "}"; + o->newline() << "#endif"; + } - Dwarf_Attribute attr_mem; - if (dwarf_attr_integrate (&vardie, DW_AT_location, &attr_mem) == NULL) - { - throw semantic_error("failed to retrieve location " - "attribute for local '" + local - + "' (dieoffset: " - + lex_cast_hex(dwarf_dieoffset (&vardie)) - + ")", - e->tok); - } + o->newline(-1) << "}"; + o->newline() << "#endif"; -#define obstack_chunk_alloc malloc -#define obstack_chunk_free free + o->newline() << "c->probe_point = 0;"; // vacated + o->newline() << "if (unlikely (c->last_error && c->last_error[0])) {"; + o->newline(1) << "if (c->last_stmt != NULL)"; + o->newline(1) << "_stp_softerror (\"%s near %s\", c->last_error, c->last_stmt);"; + o->newline(-1) << "else"; + o->newline(1) << "_stp_softerror (\"%s\", c->last_error);"; + o->indent(-1); + o->newline() << "atomic_inc (& error_count);"; + o->newline() << "if (atomic_read (& error_count) > MAXERRORS) {"; + o->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; + o->newline() << "_stp_exit ();"; + o->newline(-1) << "}"; + o->newline(-1) << "}"; + o->newline() << "atomic_dec (&c->busy);"; - struct obstack pool; - obstack_init (&pool); - struct location *tail = NULL; + o->newline(-1) << "probe_epilogue:"; // context is free + o->indent(1); - /* Given $foo->bar->baz[NN], translate the location of foo. */ + // Check for excessive skip counts. + o->newline() << "if (unlikely (atomic_read (& skipped_count) > MAXSKIPPED)) {"; + o->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; + o->newline() << "_stp_exit ();"; + o->newline(-1) << "}"; - struct location *head = translate_location (&pool, - &attr_mem, pc, fb_attr, &tail, - e); + o->newline() << "#if INTERRUPTIBLE"; + o->newline() << "preempt_enable_no_resched ();"; + o->newline() << "#else"; + o->newline() << "local_irq_restore (flags);"; + o->newline() << "#endif"; +} - if (dwarf_attr_integrate (&vardie, DW_AT_type, &attr_mem) == NULL) - throw semantic_error("failed to retrieve type " - "attribute for local '" + local + "'", - e->tok); - /* Translate the ->bar->baz[NN] parts. */ +// ------------------------------------------------------------------------ - Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem); - die = translate_components (&pool, &tail, pc, e, - die, &die_mem, &attr_mem); +// ------------------------------------------------------------------------ +// Dwarf derived probes. "We apologize for the inconvience." +// ------------------------------------------------------------------------ - /* Translate the assignment part, either - x = $foo->bar->baz[NN] - or - $foo->bar->baz[NN] = x - */ +static string TOK_KERNEL("kernel"); +static string TOK_MODULE("module"); +static string TOK_FUNCTION("function"); +static string TOK_INLINE("inline"); +static string TOK_CALL("call"); +static string TOK_RETURN("return"); +static string TOK_MAXACTIVE("maxactive"); +static string TOK_STATEMENT("statement"); +static string TOK_ABSOLUTE("absolute"); +static string TOK_PROCESS("process"); +static string TOK_MARK("mark"); +static string TOK_TRACE("trace"); +static string TOK_LABEL("label"); - string prelude, postlude; - translate_final_fetch_or_store (&pool, &tail, module_bias, - die, &attr_mem, lvalue, e, - prelude, postlude, ty); +// Can we handle this query with just symbol-table info? +enum dbinfo_reqt +{ + dbr_unknown, + dbr_none, // kernel.statement(NUM).absolute + dbr_need_symtab, // can get by with symbol table if there's no dwarf + dbr_need_dwarf +}; - /* Write the translation to a string. */ - return express_as_string(prelude, postlude, head); - } +struct base_query; // forward decls +struct dwarf_query; +struct dwflpp; +struct symbol_table; - string - literal_stmt_for_return (Dwarf_Die *scope_die, - Dwarf_Addr pc, - const target_symbol *e, - bool lvalue, - exp_type & ty) - { - if (sess.verbose>2) - clog << "literal_stmt_for_return: finding return value for " - << (dwarf_diename(scope_die) ?: "") - << "(" - << (dwarf_diename(cu) ?: "") - << ")\n"; - - struct obstack pool; - obstack_init (&pool); - struct location *tail = NULL; - - /* Given $return->bar->baz[NN], translate the location of return. */ - const Dwarf_Op *locops; - int nlocops = dwfl_module_return_value_location (module, scope_die, - &locops); - if (nlocops < 0) - { - throw semantic_error("failed to retrieve return value location" - " for " - + string(dwarf_diename(scope_die) ?: "") - + "(" + string(dwarf_diename(cu) ?: "") - + ")", - e->tok); - } - // the function has no return value (e.g. "void" in C) - else if (nlocops == 0) - { - throw semantic_error("function " - + string(dwarf_diename(scope_die) ?: "") - + "(" + string(dwarf_diename(cu) ?: "") - + ") has no return value", - e->tok); - } - struct location *head = c_translate_location (&pool, &loc2c_error, this, - &loc2c_emit_address, - 1, 0 /* PR9768 */, - pc, locops, nlocops, - &tail, NULL); - - /* Translate the ->bar->baz[NN] parts. */ - - Dwarf_Attribute attr_mem; - if (dwarf_attr_integrate (scope_die, DW_AT_type, &attr_mem) == NULL) - throw semantic_error("failed to retrieve return value type attribute for " - + string(dwarf_diename(scope_die) ?: "") - + "(" + string(dwarf_diename(cu) ?: "") - + ")", - e->tok); - - Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem); - die = translate_components (&pool, &tail, pc, e, - die, &die_mem, &attr_mem); - - /* Translate the assignment part, either - x = $return->bar->baz[NN] - or - $return->bar->baz[NN] = x - */ - - string prelude, postlude; - translate_final_fetch_or_store (&pool, &tail, module_bias, - die, &attr_mem, lvalue, e, - prelude, postlude, ty); - - /* Write the translation to a string. */ - return express_as_string(prelude, postlude, head); - } +struct +symbol_table +{ + module_info *mod_info; // associated module + map map_by_name; + vector list_by_addr; + typedef vector::iterator iterator_t; + typedef pair range_t; +#ifdef __powerpc__ + GElf_Word opd_section; +#endif + // add_symbol doesn't leave symbol table in order; call + // symbol_table::sort() when done adding symbols. + void add_symbol(const char *name, bool weak, Dwarf_Addr addr, + Dwarf_Addr *high_addr); + void sort(); + enum info_status read_symbols(FILE *f, const string& path); + enum info_status read_from_elf_file(const string& path); + enum info_status read_from_text_file(const string& path); + enum info_status get_from_elf(); + void prepare_section_rejection(Dwfl_Module *mod); + bool reject_section(GElf_Word section); + void mark_dwarf_redundancies(dwflpp *dw); + void purge_syscall_stubs(); + func_info *lookup_symbol(const string& name); + Dwarf_Addr lookup_symbol_address(const string& name); + func_info *get_func_containing_address(Dwarf_Addr addr); + symbol_table(module_info *mi) : mod_info(mi) {} + ~symbol_table(); +}; - string - literal_stmt_for_pointer (Dwarf_Die *type_die, - const target_symbol *e, - bool lvalue, - exp_type & ty) - { - if (sess.verbose>2) - clog << "literal_stmt_for_pointer: finding value for " - << (dwarf_diename(type_die) ?: "") - << "(" - << (dwarf_diename(cu) ?: "") - << ")\n"; - - struct obstack pool; - obstack_init (&pool); - struct location *head = c_translate_argument (&pool, &loc2c_error, this, - &loc2c_emit_address, - 1, "THIS->pointer"); - struct location *tail = head; - - /* Translate the ->bar->baz[NN] parts. */ - - Dwarf_Attribute attr_mem; - Dwarf_Die die_mem, *die = NULL; - die = translate_components (&pool, &tail, 0, e, - type_die, &die_mem, &attr_mem); - - /* Translate the assignment part, either - x = (THIS->pointer)->bar->baz[NN] - or - (THIS->pointer)->bar->baz[NN] = x - */ - - string prelude, postlude; - translate_final_fetch_or_store (&pool, &tail, module_bias, - die, &attr_mem, lvalue, e, - prelude, postlude, ty); - - /* Write the translation to a string. */ - return express_as_string(prelude, postlude, head); - } +static bool null_die(Dwarf_Die *die) +{ + static Dwarf_Die null = { 0 }; + return (!die || !memcmp(die, &null, sizeof(null))); +} - ~dwflpp() - { - if (dwfl) - dwfl_end(dwfl); - } -}; +// PR 9941 introduces the need for a predicate +int dwfl_report_offline_predicate (const char* modname, const char* filename) +{ + if (pending_interrupts) { return -1; } + return 1; +} enum @@ -2579,264 +612,6 @@ struct dwarf_query : public base_query }; -// This little test routine represents an unfortunate breakdown in -// abstraction between dwflpp (putatively, a layer right on top of -// elfutils), and dwarf_query (interpreting a systemtap probe point). -// It arises because we sometimes try to fix up slightly-off -// .statement() probes (something we find out in fairly low-level). -// -// An alternative would be to put some more intelligence into query_cu(), -// and have it print additional suggestions after finding that -// q->dw.iterate_over_srcfile_lines resulted in no new finished_results. - -bool -dwflpp::has_single_line_record (dwarf_query * q, char const * srcfile, int lineno) -{ - if (lineno < 0) - return false; - - Dwarf_Line **srcsp = NULL; - size_t nsrcs = 0; - - dwarf_assert ("dwarf_getsrc_file", - dwarf_getsrc_file (module_dwarf, - srcfile, lineno, 0, - &srcsp, &nsrcs)); - - if (nsrcs != 1) - { - if (sess.verbose>4) - clog << "alternative line " << lineno << " rejected: nsrcs=" << nsrcs << endl; - return false; - } - - // We also try to filter out lines that leave the selected - // functions (if any). - - dwarf_line_t line(srcsp[0]); - Dwarf_Addr addr = line.addr(); - - for (func_info_map_t::iterator i = q->filtered_functions.begin(); - i != q->filtered_functions.end(); ++i) - { - if (q->dw.die_has_pc (i->die, addr)) - { - if (q->sess.verbose>4) - clog << "alternative line " << lineno << " accepted: fn=" << i->name << endl; - return true; - } - } - - for (inline_instance_map_t::iterator i = q->filtered_inlines.begin(); - i != q->filtered_inlines.end(); ++i) - { - if (q->dw.die_has_pc (i->die, addr)) - { - if (sess.verbose>4) - clog << "alternative line " << lineno << " accepted: ifn=" << i->name << endl; - return true; - } - } - - if (sess.verbose>4) - clog << "alternative line " << lineno << " rejected: leaves selected fns" << endl; - return false; - } - -/* This basically only goes one level down from the compile unit so it - * only picks up top level stuff (i.e. nothing in a lower scope) */ -int -dwflpp::iterate_over_globals (int (* callback)(Dwarf_Die *, void *), - void * data) -{ - int rc = DWARF_CB_OK; - Dwarf_Die die; - - assert (module); - assert (cu); - assert (dwarf_tag(cu) == DW_TAG_compile_unit); - - if (dwarf_child(cu, &die) != 0) - return rc; - - do - /* We're only currently looking for named types, - * although other types of declarations exist */ - switch (dwarf_tag(&die)) - { - case DW_TAG_base_type: - case DW_TAG_enumeration_type: - case DW_TAG_structure_type: - case DW_TAG_typedef: - case DW_TAG_union_type: - rc = (*callback)(&die, data); - break; - } - while (rc == DWARF_CB_OK && dwarf_siblingof(&die, &die) == 0); - - return rc; -} - -int -dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, base_query * q), - base_query * q, const string& function, - bool has_statement_num) -{ - int rc = DWARF_CB_OK; - assert (module); - assert (cu); - - string key = module_name + ":" + cu_name; - cu_function_cache_t *v = cu_function_cache[key]; - if (v == 0) - { - v = new cu_function_cache_t; - cu_function_cache[key] = v; - dwarf_getfuncs (cu, cu_function_caching_callback, v, 0); - if (q->sess.verbose > 4) - clog << "function cache " << key << " size " << v->size() << endl; - } - - string subkey = function; - if (v->find(subkey) != v->end()) - { - Dwarf_Die die = v->find(subkey)->second; - if (q->sess.verbose > 4) - clog << "function cache " << key << " hit " << subkey << endl; - return (*callback)(& die, q); - } - else if (name_has_wildcard (subkey)) - { - for (cu_function_cache_t::iterator it = v->begin(); it != v->end(); it++) - { - if (pending_interrupts) return DWARF_CB_ABORT; - string func_name = it->first; - Dwarf_Die die = it->second; - if (function_name_matches_pattern (func_name, subkey)) - { - if (q->sess.verbose > 4) - clog << "function cache " << key << " match " << func_name << " vs " << subkey << endl; - - rc = (*callback)(& die, q); - if (rc != DWARF_CB_OK) break; - } - } - } - else if (has_statement_num) // searching all for kernel.statement - { - for (cu_function_cache_t::iterator it = v->begin(); it != v->end(); it++) - { - Dwarf_Die die = it->second; - rc = (*callback)(& die, q); - if (rc != DWARF_CB_OK) break; - } - } - else // not a wildcard and no match in this CU - { - // do nothing - } - return rc; -} - - -void -dwflpp::iterate_over_labels (Dwarf_Die *begin_die, - void *data, - void (* callback)(const string &, - const char *, - int, - Dwarf_Die *, - Dwarf_Addr, - dwarf_query *)) -{ - dwarf_query * q __attribute__ ((unused)) = static_cast(data) ; - - get_module_dwarf(); - - const char * sym = q->label_val.c_str(); - Dwarf_Die die; - int res = dwarf_child (begin_die, &die); - if (res != 0) - return; // die without children, bail out. - - static string function_name = dwarf_diename (begin_die); - do - { - Dwarf_Attribute attr_mem; - Dwarf_Attribute *attr = dwarf_attr (&die, DW_AT_name, &attr_mem); - int tag = dwarf_tag(&die); - const char *name = dwarf_formstring (attr); - if (name == 0) - continue; - switch (tag) - { - case DW_TAG_label: - break; - case DW_TAG_subprogram: - if (!dwarf_hasattr(&die, DW_AT_declaration)) - function_name = name; - else - continue; - default: - if (dwarf_haschildren (&die)) - iterate_over_labels (&die, q, callback); - continue; - } - - if (strcmp(function_name.c_str(), q->function.c_str()) == 0 - || (name_has_wildcard(q->function) - && function_name_matches_pattern (function_name, q->function))) - { - } - else - continue; - if (strcmp(name, sym) == 0 - || (name_has_wildcard(sym) - && function_name_matches_pattern (name, sym))) - { - const char *file = dwarf_decl_file (&die); - // Get the line number for this label - Dwarf_Attribute attr; - dwarf_attr (&die,DW_AT_decl_line, &attr); - Dwarf_Sword dline; - dwarf_formsdata (&attr, &dline); - Dwarf_Addr stmt_addr; - if (dwarf_lowpc (&die, &stmt_addr) != 0) - { - // There is no lowpc so figure out the address - // Get the real die for this cu - Dwarf_Die cudie; - dwarf_diecu (q->dw.cu, &cudie, NULL, NULL); - size_t nlines = 0; - // Get the line for this label - Dwarf_Line **aline; - dwarf_getsrc_file (module_dwarf, file, (int)dline, 0, &aline, &nlines); - // Get the address - for (size_t i = 0; i < nlines; i++) - { - dwarf_lineaddr (*aline, &stmt_addr); - if ((dwarf_haspc (&die, stmt_addr))) - break; - } - } - - Dwarf_Die *scopes; - int nscopes = 0; - nscopes = dwarf_getscopes_die (&die, &scopes); - if (nscopes > 1) - { - callback(function_name.c_str(), file, - (int)dline, &scopes[1], stmt_addr, q); - if (sess.listing_mode) - q->results.back()->locations[0]->components.push_back - (new probe_point::component(TOK_LABEL, new literal_string (name))); - } - } - } - while (dwarf_siblingof (&die, &die) == 0); -} - - struct dwarf_builder: public derived_probe_builder { dwflpp *kern_dw; @@ -2934,6 +709,30 @@ dwarf_query::dwarf_query(systemtap_session & sess, } +func_info_map_t * +get_filtered_functions(dwarf_query *q) +{ + return &q->filtered_functions; +} + + +inline_instance_map_t * +get_filtered_inlines(dwarf_query *q) +{ + return &q->filtered_inlines; +} + + +void +add_label_name(dwarf_query *q, const char *name) +{ + // this is a kludge to let the listing mode show labels to the user + if (q->sess.listing_mode) + q->results.back()->locations[0]->components.push_back + (new probe_point::component(TOK_LABEL, new literal_string (name))); +} + + void dwarf_query::query_module_dwarf() { @@ -3663,7 +1462,8 @@ query_srcfile_label (const dwarf_line_t& line, void * arg) for (func_info_map_t::iterator i = q->filtered_functions.begin(); i != q->filtered_functions.end(); ++i) if (q->dw.die_has_pc (i->die, addr)) - q->dw.iterate_over_labels (&i->die, q, query_statement); + q->dw.iterate_over_labels (&i->die, q->label_val.c_str(), q->function.c_str(), + q, query_statement); } static void @@ -3838,7 +1638,7 @@ query_dwarf_func (Dwarf_Die * func, base_query * bq) } } -static int +int query_cu (Dwarf_Die * cudie, void * arg) { dwarf_query * q = static_cast(arg); @@ -3913,7 +1713,8 @@ query_cu (Dwarf_Die * cudie, void * arg) if (q->has_label) { if (q->line[0] == 0) // No line number specified - q->dw.iterate_over_labels (q->dw.cu, q, query_statement); + q->dw.iterate_over_labels (q->dw.cu, q->label_val.c_str(), q->function.c_str(), + q, query_statement); else for (set::const_iterator i = q->filtered_srcfiles.begin(); i != q->filtered_srcfiles.end(); ++i) @@ -4093,7 +1894,7 @@ lookup_symbol_address (Dwfl_Module *m, const char* wanted) -static int +int query_module (Dwfl_Module *mod, void **, const char *name, @@ -4187,12 +1988,6 @@ query_module (Dwfl_Module *mod, } } -void -dwflpp::query_modules(base_query *q) -{ - iterate_over_modules(&query_module, q); -} - struct dwarf_var_expanding_visitor: public var_expanding_visitor { -- cgit From b6fa229bc4b361a23f23daa13af634a0515230d6 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 15 May 2009 13:14:52 -0700 Subject: Merge the dwflpp::query_cu_..._address methods The method query_cu_containing_global_address was only called by query_cu_containing_module_address, and the latter was just doing a simple argument transform. They are now merged into a single method, query_cu_containing_address. The function module_address_to_global is also merged here at its only call site. --- tapsets.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 3aad1730..3437205f 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -751,7 +751,7 @@ dwarf_query::query_module_dwarf() // NB: we don't need to add the module base address or bias // value here (for reasons that may be coincidental). - dw.query_cu_containing_module_address(addr, this); + dw.query_cu_containing_address(addr, this); } else { -- cgit From 511785011b1bd7092d9e093f6e954c131d83a3a0 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 15 May 2009 14:10:57 -0700 Subject: Break the dwflpp dependence on query_module --- tapsets.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 3437205f..25b729d8 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1894,7 +1894,7 @@ lookup_symbol_address (Dwfl_Module *m, const char* wanted) -int +static int query_module (Dwfl_Module *mod, void **, const char *name, @@ -2756,7 +2756,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) } dwarf_cast_query q (*dw, module, *e, lvalue, type, code); - dw->query_modules(&q); + dw->iterate_over_modules(&query_module, &q); } if (code.empty()) @@ -3497,7 +3497,7 @@ dwarf_builder::build(systemtap_session & sess, dwarf_query q(sess, base, location, *dw, parameters, finished_results); q.has_mark = true; - dw->query_modules(&q); + dw->iterate_over_modules(&query_module, &q); if (sess.listing_mode) { finished_results.back()->locations[0]->components[1]->functor = TOK_MARK; @@ -3554,7 +3554,7 @@ dwarf_builder::build(systemtap_session & sess, return; } - dw->query_modules(&q); + dw->iterate_over_modules(&query_module, &q); } symbol_table::~symbol_table() @@ -5700,7 +5700,7 @@ tracepoint_builder::build(systemtap_session& s, assert(get_param (parameters, TOK_TRACE, tracepoint)); tracepoint_query q(*dw, tracepoint, base, location, finished_results); - dw->query_modules(&q); + dw->iterate_over_modules(&query_module, &q); } -- cgit From 1adf8ef1ca448709a7a4527b916d65ada0b3fc04 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 15 May 2009 14:26:32 -0700 Subject: Break the dwflpp dependence on query_cu --- tapsets.cxx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 25b729d8..eeccb90b 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -260,6 +260,8 @@ static string TOK_MARK("mark"); static string TOK_TRACE("trace"); static string TOK_LABEL("label"); +static int query_cu (Dwarf_Die * cudie, void * arg); + // Can we handle this query with just symbol-table info? enum dbinfo_reqt { @@ -751,7 +753,9 @@ dwarf_query::query_module_dwarf() // NB: we don't need to add the module base address or bias // value here (for reasons that may be coincidental). - dw.query_cu_containing_address(addr, this); + Dwarf_Die* cudie = dw.query_cu_containing_address(addr); + if (cudie) // address could be wildly out of range + query_cu(cudie, this); } else { @@ -1638,7 +1642,7 @@ query_dwarf_func (Dwarf_Die * func, base_query * bq) } } -int +static int query_cu (Dwarf_Die * cudie, void * arg) { dwarf_query * q = static_cast(arg); -- cgit From 4627ed58020162dc8c0798dcfa24d3756eee5ccf Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 15 May 2009 18:59:16 -0700 Subject: Make all tapsets' TOK_FOO constant --- tapsets.cxx | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 1728ec9e..a9ef2487 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -246,19 +246,19 @@ common_probe_entryfn_epilogue (translator_output* o, // Dwarf derived probes. "We apologize for the inconvience." // ------------------------------------------------------------------------ -static string TOK_KERNEL("kernel"); -static string TOK_MODULE("module"); -static string TOK_FUNCTION("function"); -static string TOK_INLINE("inline"); -static string TOK_CALL("call"); -static string TOK_RETURN("return"); -static string TOK_MAXACTIVE("maxactive"); -static string TOK_STATEMENT("statement"); -static string TOK_ABSOLUTE("absolute"); -static string TOK_PROCESS("process"); -static string TOK_MARK("mark"); -static string TOK_TRACE("trace"); -static string TOK_LABEL("label"); +static const string TOK_KERNEL("kernel"); +static const string TOK_MODULE("module"); +static const string TOK_FUNCTION("function"); +static const string TOK_INLINE("inline"); +static const string TOK_CALL("call"); +static const string TOK_RETURN("return"); +static const string TOK_MAXACTIVE("maxactive"); +static const string TOK_STATEMENT("statement"); +static const string TOK_ABSOLUTE("absolute"); +static const string TOK_PROCESS("process"); +static const string TOK_MARK("mark"); +static const string TOK_TRACE("trace"); +static const string TOK_LABEL("label"); static int query_cu (Dwarf_Die * cudie, void * arg); @@ -4461,7 +4461,7 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) // Kprobe derived probes // ------------------------------------------------------------------------ -static string TOK_KPROBE("kprobe"); +static const string TOK_KPROBE("kprobe"); struct kprobe_derived_probe: public derived_probe { -- cgit From b350f56b13f4e5acd5744cd71e4b26343aae8e6b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 22 May 2009 18:01:18 -0700 Subject: PR10190: Suppress warnings for optional kprobes When a kernel.function or kprobe.function fails in registration, we usually print a WARNING and move on. With this patch, kprobes that have the optional '?' flag will not print any WARNING. --- tapsets.cxx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index a9ef2487..5335ea9c 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3103,6 +3103,7 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "static struct stap_dwarf_probe {"; s.op->newline(1) << "const unsigned return_p:1;"; s.op->newline() << "const unsigned maxactive_p:1;"; + s.op->newline() << "const unsigned optional_p:1;"; s.op->newline() << "unsigned registered_p:1;"; s.op->newline() << "const unsigned short maxactive_val;"; @@ -3163,6 +3164,8 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) assert (p->maxactive_val >= 0 && p->maxactive_val <= USHRT_MAX); s.op->line() << " .maxactive_val=" << p->maxactive_val << ","; } + if (p->locations[0]->optional) + s.op->line() << " .optional_p=1,"; s.op->line() << " .address=(unsigned long)0x" << hex << p->addr << dec << "ULL,"; s.op->line() << " .module=\"" << p->module << "\","; s.op->line() << " .section=\"" << p->section << "\","; @@ -3266,8 +3269,9 @@ dwarf_derived_probe_group::emit_module_init (systemtap_session& s) s.op->newline(-1) << "}"; s.op->newline() << "if (rc) {"; // PR6749: tolerate a failed register_*probe. s.op->newline(1) << "sdp->registered_p = 0;"; - s.op->newline() << "_stp_warn (\"probe %s registration error (rc %d)\", probe_point, rc);"; - s.op->newline() << "rc = 0;"; // continue with other probes + s.op->newline() << "if (!sdp->optional_p)"; + s.op->newline(1) << "_stp_warn (\"probe %s registration error (rc %d)\", probe_point, rc);"; + s.op->newline(-1) << "rc = 0;"; // continue with other probes // XXX: shall we increment numskipped? s.op->newline(-1) << "}"; @@ -4611,6 +4615,7 @@ kprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "static struct stap_dwarfless_probe {"; s.op->newline(1) << "const unsigned return_p:1;"; s.op->newline() << "const unsigned maxactive_p:1;"; + s.op->newline() << "const unsigned optional_p:1;"; s.op->newline() << "unsigned registered_p:1;"; s.op->newline() << "const unsigned short maxactive_val;"; @@ -4657,6 +4662,9 @@ kprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->line() << " .maxactive_val=" << p->maxactive_val << ","; } + if (p->locations[0]->optional) + s.op->line() << " .optional_p=1,"; + if (p->has_statement) s.op->line() << " .address=(unsigned long)0x" << hex << p->addr << dec << "ULL,"; else @@ -4766,8 +4774,9 @@ kprobe_derived_probe_group::emit_module_init (systemtap_session& s) s.op->newline(-1) << "}"; s.op->newline() << "if (rc) {"; // PR6749: tolerate a failed register_*probe. s.op->newline(1) << "sdp->registered_p = 0;"; - s.op->newline() << "_stp_warn (\"probe %s registration error (rc %d)\", probe_point, rc);"; - s.op->newline() << "rc = 0;"; // continue with other probes + s.op->newline() << "if (!sdp->optional_p)"; + s.op->newline(1) << "_stp_warn (\"probe %s registration error (rc %d)\", probe_point, rc);"; + s.op->newline(-1) << "rc = 0;"; // continue with other probes // XXX: shall we increment numskipped? s.op->newline(-1) << "}"; -- cgit From c9116e9980ad6e417697737f8d54a4a625811245 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 22 May 2009 19:55:50 -0700 Subject: Fix another kernel/kprobe.function conflict Both kernel.function and kprobe.function were defining a global array stap_unreg_kprobes to use in bulk kprobes unregistration. The compiler allowed the duplicate definition as long as they were the same size, as it was when exercised in buildok/thirtyone. kprobe.function now uses a separate stap_unreg_kprobes2, and the testcase is modified to produce an imbalanced number of probes. --- tapsets.cxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 5335ea9c..e88928dc 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -4599,7 +4599,7 @@ kprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // Emit an array of kprobe/kretprobe pointers s.op->newline() << "#if defined(STAPCONF_UNREGISTER_KPROBES)"; - s.op->newline() << "static void * stap_unreg_kprobes[" << probes_by_module.size() << "];"; + s.op->newline() << "static void * stap_unreg_kprobes2[" << probes_by_module.size() << "];"; s.op->newline() << "#endif"; // Emit the actual probe list. @@ -4795,27 +4795,27 @@ kprobe_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];"; s.op->newline() << "if (! sdp->registered_p) continue;"; s.op->newline() << "if (!sdp->return_p)"; - s.op->newline(1) << "stap_unreg_kprobes[j++] = &kp->u.kp;"; + s.op->newline(1) << "stap_unreg_kprobes2[j++] = &kp->u.kp;"; s.op->newline(-2) << "}"; - s.op->newline() << "unregister_kprobes((struct kprobe **)stap_unreg_kprobes, j);"; + s.op->newline() << "unregister_kprobes((struct kprobe **)stap_unreg_kprobes2, j);"; s.op->newline() << "j = 0;"; s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {"; s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];"; s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];"; s.op->newline() << "if (! sdp->registered_p) continue;"; s.op->newline() << "if (sdp->return_p)"; - s.op->newline(1) << "stap_unreg_kprobes[j++] = &kp->u.krp;"; + s.op->newline(1) << "stap_unreg_kprobes2[j++] = &kp->u.krp;"; s.op->newline(-2) << "}"; - s.op->newline() << "unregister_kretprobes((struct kretprobe **)stap_unreg_kprobes, j);"; + s.op->newline() << "unregister_kretprobes((struct kretprobe **)stap_unreg_kprobes2, j);"; s.op->newline() << "#ifdef __ia64__"; s.op->newline() << "j = 0;"; s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {"; s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];"; s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];"; s.op->newline() << "if (! sdp->registered_p) continue;"; - s.op->newline() << "stap_unreg_kprobes[j++] = &kp->dummy;"; + s.op->newline() << "stap_unreg_kprobes2[j++] = &kp->dummy;"; s.op->newline(-1) << "}"; - s.op->newline() << "unregister_kprobes((struct kprobe **)stap_unreg_kprobes, j);"; + s.op->newline() << "unregister_kprobes((struct kprobe **)stap_unreg_kprobes2, j);"; s.op->newline() << "#endif"; s.op->newline() << "#endif"; -- cgit From 276465828851648edc5b56f762a0d100051c9e32 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 1 Jun 2009 18:47:30 -0700 Subject: Move the blacklist functions into dwflpp For a call like "stap -l 'syscall.*'", I found that ~10% of the time was spent compiling the blacklist regexps over again for each probe point. By moving this functionality into the kernel dwflpp instance, we can reuse the regexps and get an easy speed boost. --- tapsets.cxx | 324 +----------------------------------------------------------- 1 file changed, 4 insertions(+), 320 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index e88928dc..f83924ab 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -43,7 +43,6 @@ extern "C" { #include #include #include -#include #include #include #include @@ -550,19 +549,6 @@ struct dwarf_query : public base_query int line, Dwarf_Die *scope_die, Dwarf_Addr addr); - string get_blacklist_section(Dwarf_Addr addr); - - regex_t blacklist_func; // function/statement probes - regex_t blacklist_func_ret; // only for .return probes - regex_t blacklist_file; // file name - void build_blacklist(); - - bool blacklisted_p(const string& funcname, - const string& filename, - int line, - const string& module, - const string& section, - Dwarf_Addr addr); // Extracted parameters. string function_val; @@ -705,7 +691,6 @@ dwarf_query::dwarf_query(systemtap_session & sess, else if (has_statement_str) spec_type = parse_function_spec(statement_str_val); - build_blacklist(); // XXX: why not reuse amongst dwarf_query instances? dbinfo_reqt = assess_dbinfo_reqt(); query_done = false; } @@ -872,138 +857,6 @@ 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. - - string blfn = "^("; - string blfn_ret = "^("; - string blfile = "^("; - - blfile += "kernel/kprobes.c"; // first alternative, no "|" - blfile += "|arch/.*/kernel/kprobes.c"; - // Older kernels need ... - blfile += "|include/asm/io.h"; - blfile += "|include/asm/bitops.h"; - // While newer ones need ... - blfile += "|arch/.*/include/asm/io.h"; - blfile += "|arch/.*/include/asm/bitops.h"; - blfile += "|drivers/ide/ide-iops.c"; - - // XXX: it would be nice if these blacklisted functions were pulled - // in dynamically, instead of being statically defined here. - // Perhaps it could be populated from script files. A "noprobe - // kernel.function("...")" construct might do the trick. - - // Most of these are marked __kprobes in newer kernels. We list - // them here (anyway) so the translator can block them on older - // kernels that don't have the __kprobes function decorator. This - // also allows detection of problems at translate- rather than - // run-time. - - blfn += "atomic_notifier_call_chain"; // first blfn; no "|" - blfn += "|default_do_nmi"; - blfn += "|__die"; - blfn += "|die_nmi"; - blfn += "|do_debug"; - blfn += "|do_general_protection"; - blfn += "|do_int3"; - blfn += "|do_IRQ"; - blfn += "|do_page_fault"; - blfn += "|do_sparc64_fault"; - blfn += "|do_trap"; - blfn += "|dummy_nmi_callback"; - blfn += "|flush_icache_range"; - blfn += "|ia64_bad_break"; - blfn += "|ia64_do_page_fault"; - blfn += "|ia64_fault"; - blfn += "|io_check_error"; - blfn += "|mem_parity_error"; - blfn += "|nmi_watchdog_tick"; - blfn += "|notifier_call_chain"; - blfn += "|oops_begin"; - blfn += "|oops_end"; - blfn += "|program_check_exception"; - blfn += "|single_step_exception"; - blfn += "|sync_regs"; - blfn += "|unhandled_fault"; - blfn += "|unknown_nmi_error"; - - // Lots of locks - blfn += "|.*raw_.*lock.*"; - blfn += "|.*read_.*lock.*"; - blfn += "|.*write_.*lock.*"; - blfn += "|.*spin_.*lock.*"; - blfn += "|.*rwlock_.*lock.*"; - blfn += "|.*rwsem_.*lock.*"; - blfn += "|.*mutex_.*lock.*"; - blfn += "|raw_.*"; - blfn += "|.*seq_.*lock.*"; - - // atomic functions - blfn += "|atomic_.*"; - blfn += "|atomic64_.*"; - - // few other problematic cases - blfn += "|get_bh"; - blfn += "|put_bh"; - - // Experimental - blfn += "|.*apic.*|.*APIC.*"; - blfn += "|.*softirq.*"; - blfn += "|.*IRQ.*"; - blfn += "|.*_intr.*"; - blfn += "|__delay"; - blfn += "|.*kernel_text.*"; - blfn += "|get_current"; - blfn += "|current_.*"; - blfn += "|.*exception_tables.*"; - blfn += "|.*setup_rt_frame.*"; - - // PR 5759, CONFIG_PREEMPT kernels - blfn += "|.*preempt_count.*"; - blfn += "|preempt_schedule"; - - // These functions don't return, so return probes would never be recovered - blfn_ret += "do_exit"; // no "|" - blfn_ret += "|sys_exit"; - blfn_ret += "|sys_exit_group"; - - // __switch_to changes "current" on x86_64 and i686, so return probes - // would cause kernel panic, and it is marked as "__kprobes" on x86_64 - if (sess.architecture == "x86_64") - blfn += "|__switch_to"; - if (sess.architecture == "i686") - blfn_ret += "|__switch_to"; - - blfn += ")$"; - blfn_ret += ")$"; - blfile += ")$"; - - if (sess.verbose > 2) - { - clog << "blacklist regexps:" << endl; - clog << "blfn: " << blfn << endl; - clog << "blfn_ret: " << blfn_ret << endl; - clog << "blfile: " << blfile << endl; - } - - int rc = regcomp (& blacklist_func, blfn.c_str(), REG_NOSUB|REG_EXTENDED); - if (rc) throw semantic_error ("blacklist_func regcomp failed"); - rc = regcomp (& blacklist_func_ret, blfn_ret.c_str(), REG_NOSUB|REG_EXTENDED); - if (rc) throw semantic_error ("blacklist_func_ret regcomp failed"); - rc = regcomp (& blacklist_file, blfile.c_str(), REG_NOSUB|REG_EXTENDED); - if (rc) throw semantic_error ("blacklist_file regcomp failed"); -} - - function_spec_type dwarf_query::parse_function_spec(string & spec) { @@ -1094,129 +947,6 @@ dwarf_query::parse_function_spec(string & spec) } -#if 0 -// Forward declaration. -static int query_kernel_module (Dwfl_Module *, void **, const char *, - Dwarf_Addr, void *); -#endif - - -// XXX: pull this into dwflpp -static bool -in_kprobes_function(systemtap_session& sess, Dwarf_Addr addr) -{ - if (sess.sym_kprobes_text_start != 0 && sess.sym_kprobes_text_end != 0) - { - // If the probe point address is anywhere in the __kprobes - // address range, we can't use this probe point. - if (addr >= sess.sym_kprobes_text_start && addr < sess.sym_kprobes_text_end) - return true; - } - return false; -} - - -bool -dwarf_query::blacklisted_p(const string& funcname, - const string& filename, - int, - const string& module, - 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.") || - section.substr(0, 9) == string(".devexit.") || - section.substr(0, 9) == string(".cpuinit.") || - section.substr(0, 9) == string(".cpuexit.") || - section.substr(0, 9) == string(".meminit.") || - section.substr(0, 9) == string(".memexit.")) - { - // NB: module .exit. routines could be probed in theory: - // if the exit handler in "struct module" is diverted, - // first inserting the kprobes - // then allowing the exit code to run - // then removing these kprobes - if (sess.verbose>1) - clog << " skipping - init/exit"; - return true; - } - - // Check for function marked '__kprobes'. - if (module == TOK_KERNEL && in_kprobes_function(sess, addr)) - { - if (sess.verbose>1) - clog << " skipping - __kprobes"; - return true; - } - - // Check probe point against blacklist. - int goodfn = regexec (&blacklist_func, funcname.c_str(), 0, NULL, 0); - if (has_return) - goodfn = goodfn && regexec (&blacklist_func_ret, funcname.c_str(), 0, NULL, 0); - int goodfile = regexec (&blacklist_file, filename.c_str(), 0, NULL, 0); - - if (! (goodfn && goodfile)) - { - if (sess.guru_mode) - { - if (sess.verbose>1) - clog << " guru mode enabled - ignoring blacklist"; - } - else - { - if (sess.verbose>1) - clog << " skipping - blacklisted"; - return true; - } - } - - // This probe point is not blacklisted. - return false; -} - -string dwarf_query::get_blacklist_section(Dwarf_Addr addr) -{ - string blacklist_section; - Dwarf_Addr bias; - // We prefer dwfl_module_getdwarf to dwfl_module_getelf here, - // because dwfl_module_getelf can force costly section relocations - // we don't really need, while either will do for this purpose. - Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (dw.module, &bias)) - ?: dwfl_module_getelf (dw.module, &bias)); - - Dwarf_Addr offset = addr - bias; - if (elf) - { - Elf_Scn* scn = 0; - size_t shstrndx; - dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); - while ((scn = elf_nextscn (elf, scn)) != NULL) - { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - if (! shdr) continue; // XXX error? - - if (!(shdr->sh_flags & SHF_ALLOC)) - continue; - - GElf_Addr start = shdr->sh_addr; - GElf_Addr end = start + shdr->sh_size; - if (! (offset >= start && offset < end)) - continue; - - blacklist_section = elf_strptr (elf, shstrndx, shdr->sh_name); - break; - } - } - return blacklist_section; -} - - void dwarf_query::add_probe_point(const string& funcname, const char* filename, @@ -1225,40 +955,13 @@ dwarf_query::add_probe_point(const string& funcname, Dwarf_Addr addr) { string reloc_section; // base section for relocation purposes - Dwarf_Addr reloc_addr = addr; // relocated + Dwarf_Addr reloc_addr; // relocated string blacklist_section; // linking section for blacklist purposes const string& module = dw.module_name; // "kernel" or other assert (! has_absolute); // already handled in dwarf_builder::build() - if (!dw.module) - { - assert(module == TOK_KERNEL); - reloc_section = ""; - blacklist_section = ""; - } - else if (dwfl_module_relocations (dw.module) > 0) - { - // 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); - if (r_s) - reloc_section = r_s; - blacklist_section = reloc_section; - - if(reloc_section == "" && dwfl_module_relocations (dw.module) == 1) - { - blacklist_section = this->get_blacklist_section(addr); - reloc_section = ".dynamic"; - reloc_addr = addr; - } - } - else - { - blacklist_section = this->get_blacklist_section(addr); - reloc_section = ".absolute"; - } + reloc_addr = dw.relocate_address(addr, reloc_section, blacklist_section); if (sess.verbose > 1) { @@ -1274,7 +977,8 @@ dwarf_query::add_probe_point(const string& funcname, clog << " pc=0x" << hex << addr << dec; } - bool bad = blacklisted_p (funcname, filename, line, module, blacklist_section, addr); + bool bad = dw.blacklisted_p (funcname, filename, line, module, + blacklist_section, addr, has_return); if (sess.verbose > 1) clog << endl; @@ -1777,26 +1481,6 @@ query_cu (Dwarf_Die * cudie, void * arg) } -#if 0 -static int -query_kernel_module (Dwfl_Module *mod, - void **, - const char *name, - Dwarf_Addr, - void *arg) -{ - if (TOK_KERNEL == name) - { - Dwfl_Module **m = (Dwfl_Module **)arg; - - *m = mod; - return DWARF_CB_ABORT; - } - return DWARF_CB_OK; -} -#endif - - static void validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q) { -- cgit From 7a05f484bf0e95d41e4d52ecb8bc6052a2d1fcc3 Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Wed, 3 Jun 2009 16:10:04 -0400 Subject: * tapsets.cxx (dwarf_builder::probe_table): New. Derived from dwarf_builder::build to handle the .probes section (sdt_var_expanding_visitor): New. Expand static probe $argN. (dwarf_builder::build): Use probe_table. Add kprobe and utrace probe types. --- tapsets.cxx | 556 ++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 411 insertions(+), 145 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index f83924ab..983c12d5 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -657,8 +657,147 @@ struct dwarf_builder: public derived_probe_builder probe_point * location, literal_map_t const & parameters, vector & finished_results); + + struct probe_table + { + public: + enum probe_types + { + uprobe_type = 0x31425250, + kprobe_type = 0x32425250, + utrace_type = 0x33425250, + } probe_type; + bool have_probes; + __uint64_t probe_arg; + string mark_name; + string probe_name; + probe_table(systemtap_session & sess, dwflpp* dw, probe_point* location); + bool get_next_probe(); + + private: + systemtap_session sess; + dwflpp* dw; + probe_point* location; + Elf_Data *pdata; + size_t probe_scn_offset; + size_t probe_scn_addr; + }; }; +dwarf_builder::probe_table::probe_table(systemtap_session & sess, dwflpp* dw, probe_point* location) +{ + Elf* elf; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Dwarf_Addr bias; + size_t shstrndx; + + elf = (dwarf_getelf (dwfl_module_getdwarf (dw->module, &bias)) + ?: dwfl_module_getelf (dw->module, &bias)); + Elf_Scn *probe_scn = NULL; + + dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); + + this->dw = dw; + this->sess = sess; + this->location = location; + this->mark_name = location->components[1]->arg->tok->content; + have_probes = false; + + // Is there a .probes section? + while ((probe_scn = elf_nextscn (elf, probe_scn))) + { + shdr = gelf_getshdr (probe_scn, &shdr_mem); + assert (shdr != NULL); + + if (strcmp (elf_strptr (elf, shstrndx, shdr->sh_name), ".probes") == 0) + { + have_probes = true; + break; + } + } + + // Older versions put .probes section in the debuginfo dwarf file, + // so check if it actually exists, if not take the main elf file + if (have_probes && shdr->sh_type == SHT_NOBITS) + { + elf = dwfl_module_getelf (dw->module, &bias); + dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); + probe_scn = NULL; + while ((probe_scn = elf_nextscn (elf, probe_scn))) + { + shdr = gelf_getshdr (probe_scn, &shdr_mem); + if (strcmp (elf_strptr (elf, shstrndx, shdr->sh_name), + ".probes") == 0) + have_probes = true; + break; + } + } + + pdata = elf_getdata_rawchunk (elf, shdr->sh_offset, shdr->sh_size, ELF_T_BYTE); + probe_scn_offset = 0; + probe_scn_addr = shdr->sh_addr; + assert (pdata != NULL); + if (sess.verbose > 4) + clog << "got .probes elf scn_addr@0x" << probe_scn_addr << dec + << ", size: " << pdata->d_size << endl; +} + +bool +dwarf_builder::probe_table::get_next_probe() +{ + if (! have_probes) + return false; + + // Extract probe info from the .probes section + if (sess.verbose > 3) + clog << "probe_type == use_uprobe, use statement addr" << endl; + + while (probe_scn_offset < pdata->d_size) + { + probe_type = (enum probe_types)*((int*)((char*)pdata->d_buf + probe_scn_offset)); + if (probe_type != uprobe_type && probe_type != kprobe_type + && probe_type != utrace_type) + { + // Unless this is a mangled .probes section, this happens + // because the name of the probe comes first, followed by + // the sentinel. + if (sess.verbose > 5) + clog << "got unknown probe_type: 0x" << hex << probe_type + << dec << endl; + probe_scn_offset += sizeof(int); + continue; + } + probe_scn_offset += sizeof(int); + if (probe_scn_offset % (sizeof(__uint64_t))) + probe_scn_offset += sizeof(__uint64_t) - (probe_scn_offset % sizeof(__uint64_t)); + + probe_name = ((char*)((long)(pdata->d_buf) + (long)(*((long*)((char*)pdata->d_buf + probe_scn_offset)) - probe_scn_addr))); + probe_scn_offset += sizeof(void*); + if (probe_scn_offset % (sizeof(__uint64_t))) + probe_scn_offset += sizeof(__uint64_t) - (probe_scn_offset % sizeof(__uint64_t)); + probe_arg = *((__uint64_t*)((char*)pdata->d_buf + probe_scn_offset)); + if (sess.verbose > 4) + clog << "saw .probes " << probe_name + << "@0x" << hex << probe_arg << dec << endl; + + if (probe_scn_offset % (sizeof(__uint64_t)*2)) + probe_scn_offset = (probe_scn_offset + sizeof(__uint64_t)*2) - (probe_scn_offset % (sizeof(__uint64_t)*2)); + if ((strcmp (mark_name.c_str(), probe_name.c_str()) == 0) + || (dw->name_has_wildcard (mark_name.c_str()) + && dw->function_name_matches_pattern + (probe_name.c_str(), mark_name.c_str()))) + { + if (sess.verbose > 3) + clog << "found probe_name" << probe_name << " at 0x" + << hex << probe_arg << dec << endl; + return true; + } + else + continue; + } + return false; +} dwarf_query::dwarf_query(systemtap_session & sess, probe * base_probe, @@ -3050,6 +3189,100 @@ dwarf_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline(-1) << "}"; } +struct sdt_var_expanding_visitor: public var_expanding_visitor +{ + sdt_var_expanding_visitor(dwflpp& dw, string& probe_name, + int arg_count, bool have_reg_args): + dw (dw), probe_name (probe_name), have_reg_args (have_reg_args), + arg_count (arg_count) {} + dwflpp& dw; + string probe_name; + bool have_reg_args; + int arg_count; + + void visit_target_symbol (target_symbol* e); +}; + +void +sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) +{ + if (e->base_name == "$$name") + { + literal_string *myname = new literal_string (probe_name); + myname->tok = e->tok; + provide(myname); + return; + } + else if (e->base_name.find("$arg") == string::npos || ! have_reg_args) + { + provide(e); + return; + } + + bool lvalue = is_active_lvalue(e); + string argname = e->base_name.substr(1); + functioncall *fc = new functioncall; + + const char *argno_str = argname.substr(3).c_str(); + int argno = atoi(argno_str); // first arg is "hidden" probe name + + if (arg_count < 6) + { + fc->function = "ulong_arg"; + fc->type = pe_long; + fc->tok = e->tok; + literal_number* num = new literal_number(argno + 1); + num->tok = e->tok; + fc->args.push_back(num); + } + else // args passed as a struct + { + fc->function = "user_long"; + fc->tok = e->tok; + binary_expression *be = new binary_expression; + be->tok = e->tok; + functioncall *get_arg1 = new functioncall; + get_arg1->function = "ulong_arg"; + get_arg1->tok = e->tok; + literal_number* num = new literal_number(2); + num->tok = e->tok; + get_arg1->args.push_back(num); + + be->left = get_arg1; + be->op = "+"; + literal_number* inc = new literal_number((argno - 1) * 8); + be->right = inc; + fc->args.push_back(be); + } + + if (lvalue) + *(target_symbol_setter_functioncalls.top()) = fc; + + cast_op *cast = new cast_op; + cast->base_name = "@cast"; + cast->tok = e->tok; + cast->operand = fc; + cast->components = e->components; + char *arg_type; + if (asprintf (&arg_type, "%s_arg%d", probe_name.c_str(), argno) == -1) + return; + cast->type = arg_type; + string sdt_include_path = ""; + for (unsigned int i = 0; i < dw.sess.args.size(); i++) + if (dw.sess.args[i].find("isdt=") == 0) + sdt_include_path = dw.sess.args[i].substr(5); + if (asprintf (&arg_type, "<%s>", sdt_include_path.c_str()) == -1) + return; + cast->module = arg_type; + dwarf_builder *db = new dwarf_builder(); + dwarf_cast_expanding_visitor *v = new dwarf_cast_expanding_visitor(this->dw.sess, *db); + v->visit_cast_op(cast); + + if (cast->components.empty()) + provide(fc); + else + provide(cast); +} void dwarf_builder::build(systemtap_session & sess, @@ -3084,157 +3317,190 @@ dwarf_builder::build(systemtap_session & sess, clog << "dwarf_builder::build for " << module_name << endl; if (((probe_point::component*)(location->components[1]))->functor == TOK_MARK) - { - enum probe_types { - probes_and_dwarf = 0, // Use statement address - dwarf_no_probes = 1, // Use label name - probes_no_dwarf = 2 - }; - - int probe_type = dwarf_no_probes; - string probe_name = (char*) location->components[1]->arg->tok->content.c_str(); - if (sess.verbose > 3) - clog << "TOK_MARK: " << probe_name << endl; - - __uint64_t probe_arg = 0; - Dwarf_Addr bias; - Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (dw->module, &bias)) - ?: dwfl_module_getelf (dw->module, &bias)); - size_t shstrndx; - Elf_Scn *probe_scn = NULL; - - dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = NULL; - - // Is there a .probes section? - while ((probe_scn = elf_nextscn (elf, probe_scn))) - { - shdr = gelf_getshdr (probe_scn, &shdr_mem); - assert (shdr != NULL); - - if (strcmp (elf_strptr (elf, shstrndx, shdr->sh_name), ".probes") == 0) - { - probe_type = probes_and_dwarf; - break; - } - } - - // Older versions put .probes section in the debuginfo dwarf file, - // so check if it actually exists, if not take the main elf file - if (probe_type == probes_and_dwarf && shdr->sh_type == SHT_NOBITS) - { - elf = dwfl_module_getelf (dw->module, &bias); - dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); - probe_scn = NULL; - while ((probe_scn = elf_nextscn (elf, probe_scn))) - { - shdr = gelf_getshdr (probe_scn, &shdr_mem); - if (strcmp (elf_strptr (elf, shstrndx, shdr->sh_name), - ".probes") == 0) - break; - } - } + probe_table probe_table(sess, dw, location); + if (! probe_table.get_next_probe()) + return; + + if (sess.verbose > 3) + clog << "TOK_MARK: " << probe_table.mark_name << endl; - // We got our .probes section, extract data. - if (probe_type == probes_and_dwarf) - { - if (sess.verbose > 3) - clog << "probe_type == probes_and_dwarf, use statement addr" << endl; - - Elf_Data *pdata = elf_getdata_rawchunk (elf, shdr->sh_offset, shdr->sh_size, ELF_T_BYTE); - assert (pdata != NULL); - size_t probe_scn_offset = 0; - size_t probe_scn_addr = shdr->sh_addr; - if (sess.verbose > 4) - clog << "got .probes elf scn_addr@0x" << probe_scn_addr << dec - << ", size: " << pdata->d_size << endl; - while (probe_scn_offset < pdata->d_size) - { - const int stap_sentinel = 0x31425250; - probe_type = *((int*)((char*)pdata->d_buf + probe_scn_offset)); - if (probe_type != stap_sentinel) - { - // Unless this is a mangled .probes section, this happens - // because the name of the probe comes first, followed by - // the sentinel. - if (sess.verbose > 5) - clog << "got unknown probe_type: 0x" << hex << probe_type - << dec << endl; - probe_scn_offset += sizeof(int); - continue; - } - probe_scn_offset += sizeof(int); - if (probe_scn_offset % (sizeof(__uint64_t))) - probe_scn_offset += sizeof(__uint64_t) - (probe_scn_offset % sizeof(__uint64_t)); - - probe_name = ((char*)((long)(pdata->d_buf) + (long)(*((long*)((char*)pdata->d_buf + probe_scn_offset)) - probe_scn_addr))); - probe_scn_offset += sizeof(void*); - if (probe_scn_offset % (sizeof(__uint64_t))) - probe_scn_offset += sizeof(__uint64_t) - (probe_scn_offset % sizeof(__uint64_t)); - probe_arg = *((__uint64_t*)((char*)pdata->d_buf + probe_scn_offset)); - if (sess.verbose > 4) - clog << "saw .probes " << probe_name - << "@0x" << hex << probe_arg << dec << endl; - - if (probe_scn_offset % (sizeof(__uint64_t)*2)) - probe_scn_offset = (probe_scn_offset + sizeof(__uint64_t)*2) - (probe_scn_offset % (sizeof(__uint64_t)*2)); - if ((strcmp (location->components[1]->arg->tok->content.c_str(), - probe_name.c_str()) == 0) - || (dw->name_has_wildcard (location->components[1]->arg->tok->content.c_str()) - && dw->function_name_matches_pattern - (probe_name.c_str(), - location->components[1]->arg->tok->content.c_str()))) - { - if (sess.verbose > 3) - clog << "found probe_name" << probe_name << " at 0x" - << hex << probe_arg << dec << endl; - } - else - continue; - const token* sv_tok = location->components[1]->arg->tok; - location->components[1]->functor = TOK_STATEMENT; - location->components[1]->arg = new literal_number((long)probe_arg); - location->components[1]->arg->tok = sv_tok; - ((literal_map_t&)parameters)[TOK_STATEMENT] = location->components[1]->arg; - - if (sess.verbose > 3) - clog << "probe_type == probes_and_dwarf, use statement addr: 0x" - << hex << probe_arg << dec << endl; + if (probe_table.probe_type == probe_table.uprobe_type) + { + do + { + const token* sv_tok = location->components[1]->arg->tok; + location->components[1]->functor = TOK_STATEMENT; + location->components[1]->arg = new literal_number((long)probe_table.probe_arg); + location->components[1]->arg->tok = sv_tok; + ((literal_map_t&)parameters)[TOK_STATEMENT] = location->components[1]->arg; + + if (sess.verbose > 3) + clog << "probe_type == use_uprobe, use statement addr: 0x" + << hex << probe_table.probe_arg << dec << endl; - dwarf_query q(sess, base, location, *dw, parameters, finished_results); - q.has_mark = true; - dw->iterate_over_modules(&query_module, &q); - if (sess.listing_mode) - { - finished_results.back()->locations[0]->components[1]->functor = TOK_MARK; - finished_results.back()->locations[0]->components[1]->arg = new literal_string (probe_name.c_str()); - } - } - return; - } + // Now expand the local variables in the probe body + sdt_var_expanding_visitor svv (*dw, probe_table.mark_name, + probe_table.probe_arg, false); + base->body = svv.require (base->body); + + dwarf_query q(sess, base, location, *dw, parameters, finished_results); + q.has_mark = true; + dw->iterate_over_modules(&query_module, &q); + if (sess.listing_mode) + { + finished_results.back()->locations[0]->components[1]->functor = TOK_MARK; + finished_results.back()->locations[0]->components[1]->arg = new literal_string (probe_table.probe_name.c_str()); + } + } + while (probe_table.get_next_probe()); + return; + } - else if (probe_type == dwarf_no_probes) - { - location->components[1]->functor = TOK_FUNCTION; - location->components[1]->arg = new literal_string("*"); - ((literal_map_t&)parameters)[TOK_FUNCTION] = location->components[1]->arg; - location->components.push_back(new probe_point::component(TOK_LABEL)); - location->components[2]->arg = new literal_string("_stapprobe1_" + probe_name); - ((literal_map_t&)parameters).erase(TOK_MARK); - ((literal_map_t&)parameters).insert(pair(TOK_LABEL, location->components[2]->arg)); - - if (sess.verbose > 3) - clog << "probe_type == dwarf_no_probes, use label name: " - << "_stapprobe1_" << probe_name << endl; - } + else if (probe_table.probe_type == probe_table.kprobe_type) + { + do + { + block *b = ((block*)(base->body)); + functioncall *fc = new functioncall; + fc->function = "ulong_arg"; + fc->tok = base->body->tok; + literal_number* num = new literal_number(1); + num->tok = base->body->tok; + fc->args.push_back(num); + + functioncall *fcus = new functioncall; + fcus->function = "user_string"; + fcus->type = pe_string; + fcus->tok = base->body->tok; + fcus->args.push_back(fc); + + // Generate: if (arg1 != mark("label")) next; + if_statement *is = new if_statement; + is->thenblock = new next_statement; + is->elseblock = NULL; + is->tok = base->body->tok; + comparison *be = new comparison; + be->op = "!="; + be->tok = base->body->tok; + be->left = fcus; + be->right = new literal_string(probe_table.mark_name); + is->condition = be; + b->statements.insert(b->statements.begin(),(statement*) is); + + // Now expand the local variables in the probe body + sdt_var_expanding_visitor svv (*dw, probe_table.mark_name, + probe_table.probe_arg, true); + base->body = svv.require (base->body); + location->components[0]->functor = "kernel"; + location->components[0]->arg = NULL; + location->components[1]->functor = "function"; + location->components[1]->arg = new literal_string("*getegid*"); + ((literal_map_t&)parameters).erase(TOK_PROCESS); + ((literal_map_t&)parameters).erase(TOK_MARK); + ((literal_map_t&)parameters).insert(pair("kernel", NULL)); + ((literal_map_t&)parameters).insert(pair("function", location->components[1]->arg)); + + dw = get_kern_dw(sess); + + dwarf_query q(sess, base, location, *dw, parameters, finished_results); + q.has_mark = true; + + dw->iterate_over_modules(&query_module, &q); + } + while (probe_table.get_next_probe()); + return; + } - else if (sess.verbose > 3) - clog << "probe_type == probes_no_dwarf" << endl; + else if (probe_table.probe_type == probe_table.utrace_type) + { + do + { + block *b = ((block*)(base->body)); + + // Generate: if ($syscall != 0xbead) next; + if_statement *issc = new if_statement; + issc->thenblock = new next_statement; + issc->elseblock = NULL; + issc->tok = base->body->tok; + comparison *besc = new comparison; + besc->op = "!="; + besc->tok = base->body->tok; + functioncall* n = new functioncall; + n->tok = base->body->tok; + n->function = "_utrace_syscall_nr"; + n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session + besc->left = n; + literal_number* fake_syscall = new literal_number(0xbead); + fake_syscall->tok = base->body->tok; + besc->right = fake_syscall; + issc->condition = besc; + b->statements.insert(b->statements.begin(),(statement*) issc); + + functioncall *fc = new functioncall; + fc->function = "ulong_arg"; + fc->tok = base->body->tok; + literal_number* num = new literal_number(1); + num->tok = base->body->tok; + fc->args.push_back(num); + + functioncall *fcus = new functioncall; + fcus->function = "user_string"; + fcus->type = pe_string; + fcus->tok = base->body->tok; + fcus->args.push_back(fc); + + // Generate: if (arg1 != mark("label")) next; + if_statement *is = new if_statement; + is->thenblock = new next_statement; + is->elseblock = NULL; + is->tok = base->body->tok; + comparison *be = new comparison; + be->op = "!="; + be->tok = base->body->tok; + be->left = fcus; + be->right = new literal_string(probe_table.mark_name); + is->condition = be; + b->statements.insert(b->statements.begin(),(statement*) is); + + // Now expand the local variables in the probe body + sdt_var_expanding_visitor svv (*dw, probe_table.mark_name, + probe_table.probe_arg, true); + base->body = svv.require (base->body); + + // process("executable").syscall + location->components[1]->functor = "syscall"; + location->components[1]->arg = NULL; + ((literal_map_t&)parameters).erase(TOK_MARK); + ((literal_map_t&)parameters).insert(pair("syscall", NULL)); + + // XXX: duplicates code above + if (! kern_dw) + dw = get_kern_dw(sess); + + derive_probes(sess, base, finished_results); + } + while (probe_table.get_next_probe()); + return; + } - dw->module = 0; - } + else + { + location->components[1]->functor = TOK_FUNCTION; + location->components[1]->arg = new literal_string("*"); + ((literal_map_t&)parameters)[TOK_FUNCTION] = location->components[1]->arg; + location->components.push_back(new probe_point::component(TOK_LABEL)); + location->components[2]->arg = new literal_string("_stapprobe1_" + probe_table.mark_name); + ((literal_map_t&)parameters).erase(TOK_MARK); + ((literal_map_t&)parameters).insert(pair(TOK_LABEL, location->components[2]->arg)); + + if (sess.verbose > 3) + clog << "probe_type == use_uprobe_no_dwarf, use label name: " + << "_stapprobe1_" << probe_table.mark_name << endl; + } + + dw->module = 0; + } dwarf_query q(sess, base, location, *dw, parameters, finished_results); -- cgit From 3d022fa9c6bdbca383dfc639d08d65287c708f56 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 3 Jun 2009 18:51:30 -0700 Subject: Fix uninitialized shdr in probe_table * tapsets.cxx (dwarf_builder::probe_table::probe_table): gcc 4.4 complains that shdr may be used uninitialized. I added returns to ensure that it's ok, but gcc still complains. Set the thing to NULL as well to silence the beast. --- tapsets.cxx | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 983c12d5..50e80cf5 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -688,7 +688,7 @@ dwarf_builder::probe_table::probe_table(systemtap_session & sess, dwflpp* dw, pr { Elf* elf; GElf_Shdr shdr_mem; - GElf_Shdr *shdr; + GElf_Shdr *shdr = NULL; Dwarf_Addr bias; size_t shstrndx; @@ -703,7 +703,7 @@ dwarf_builder::probe_table::probe_table(systemtap_session & sess, dwflpp* dw, pr this->location = location; this->mark_name = location->components[1]->arg->tok->content; have_probes = false; - + // Is there a .probes section? while ((probe_scn = elf_nextscn (elf, probe_scn))) { @@ -716,14 +716,18 @@ dwarf_builder::probe_table::probe_table(systemtap_session & sess, dwflpp* dw, pr break; } } - + + if (!have_probes) + return; + // Older versions put .probes section in the debuginfo dwarf file, // so check if it actually exists, if not take the main elf file - if (have_probes && shdr->sh_type == SHT_NOBITS) + if (shdr->sh_type == SHT_NOBITS) { elf = dwfl_module_getelf (dw->module, &bias); dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); probe_scn = NULL; + have_probes = false; while ((probe_scn = elf_nextscn (elf, probe_scn))) { shdr = gelf_getshdr (probe_scn, &shdr_mem); @@ -734,6 +738,9 @@ dwarf_builder::probe_table::probe_table(systemtap_session & sess, dwflpp* dw, pr } } + if (!have_probes) + return; + pdata = elf_getdata_rawchunk (elf, shdr->sh_offset, shdr->sh_size, ELF_T_BYTE); probe_scn_offset = 0; probe_scn_addr = shdr->sh_addr; @@ -748,11 +755,11 @@ dwarf_builder::probe_table::get_next_probe() { if (! have_probes) return false; - + // Extract probe info from the .probes section if (sess.verbose > 3) clog << "probe_type == use_uprobe, use statement addr" << endl; - + while (probe_scn_offset < pdata->d_size) { probe_type = (enum probe_types)*((int*)((char*)pdata->d_buf + probe_scn_offset)); @@ -780,7 +787,7 @@ dwarf_builder::probe_table::get_next_probe() if (sess.verbose > 4) clog << "saw .probes " << probe_name << "@0x" << hex << probe_arg << dec << endl; - + if (probe_scn_offset % (sizeof(__uint64_t)*2)) probe_scn_offset = (probe_scn_offset + sizeof(__uint64_t)*2) - (probe_scn_offset % (sizeof(__uint64_t)*2)); if ((strcmp (mark_name.c_str(), probe_name.c_str()) == 0) @@ -2346,9 +2353,9 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e) saveme->chain = e->saved_conversion_error; e->saved_conversion_error = saveme; } - else + else { - // Upon user request for ignoring context, the symbol is replaced + // Upon user request for ignoring context, the symbol is replaced // with a literal 0 and a warning message displayed literal_number* ln_zero = new literal_number (0); ln_zero->tok = e->tok; @@ -3218,7 +3225,7 @@ sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) provide(e); return; } - + bool lvalue = is_active_lvalue(e); string argname = e->base_name.substr(1); functioncall *fc = new functioncall; @@ -3254,7 +3261,7 @@ sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) be->right = inc; fc->args.push_back(be); } - + if (lvalue) *(target_symbol_setter_functioncalls.top()) = fc; @@ -3321,7 +3328,7 @@ dwarf_builder::build(systemtap_session & sess, probe_table probe_table(sess, dw, location); if (! probe_table.get_next_probe()) return; - + if (sess.verbose > 3) clog << "TOK_MARK: " << probe_table.mark_name << endl; @@ -3338,7 +3345,7 @@ dwarf_builder::build(systemtap_session & sess, if (sess.verbose > 3) clog << "probe_type == use_uprobe, use statement addr: 0x" << hex << probe_table.probe_arg << dec << endl; - + // Now expand the local variables in the probe body sdt_var_expanding_visitor svv (*dw, probe_table.mark_name, probe_table.probe_arg, false); @@ -3501,7 +3508,7 @@ dwarf_builder::build(systemtap_session & sess, dw->module = 0; } - + dwarf_query q(sess, base, location, *dw, parameters, finished_results); @@ -5420,7 +5427,7 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s) } s.op->line() << ") {"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", lex_cast_qstring (*p->sole_location())); s.op->newline() << "c->marker_name = " << lex_cast_qstring (p->tracepoint_name) -- cgit From 0e14e0793ffb891bccd465cf518480685e3cd49e Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 8 Jun 2009 15:36:42 -0700 Subject: Let query_module abort early for simple matches query_module was already returning DW_CB_ABORT when a simple match was found, but dwflpp::iterate_over_modules was ignoring that and instead forcing the module loop to restart. The only way out of the loop was with the pending_interrupts flag, which is only for signalled interrupts. Now iterate_over_modules will only attempt the dwfl_getmodules loop once, since that loop will only abort if the CB returns DW_CB_ABORT. Then query_module is also modified to return ABORT if pending_interrupts is flagged. My trusty test, stap -l syscall.*, is nearly 2x faster with this change. Empirically, I found that the kernel object is always the first "module" returned, so the syscall probepoints always gets to short-circuit the loop right away. --- tapsets.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 50e80cf5..d8fe8f8e 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1776,13 +1776,13 @@ query_module (Dwfl_Module *mod, // If we have enough information in the pattern to skip a module and // the module does not match that information, return early. if (!q->dw.module_name_matches(q->module_val)) - return DWARF_CB_OK; + return pending_interrupts ? DWARF_CB_ABORT : DWARF_CB_OK; // Don't allow module("*kernel*") type expressions to match the // elfutils module "kernel", which we refer to in the probe // point syntax exclusively as "kernel.*". if (q->dw.module_name == TOK_KERNEL && ! q->has_kernel) - return DWARF_CB_OK; + return pending_interrupts ? DWARF_CB_ABORT : DWARF_CB_OK; if (mod) validate_module_elf(mod, name, q); @@ -1810,7 +1810,7 @@ query_module (Dwfl_Module *mod, // If we know that there will be no more matches, abort early. - if (q->dw.module_name_final_match(q->module_val)) + if (q->dw.module_name_final_match(q->module_val) || pending_interrupts) return DWARF_CB_ABORT; else return DWARF_CB_OK; -- cgit From ad002306b50c6cc3c3601fac31dfe3ecf23749fb Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Mon, 8 Jun 2009 21:57:44 -0400 Subject: * tapsets.cxx (probe_table): Make mark_name and sess refs. (probe_table::get_next_probe): Dissect using struct probe_table. (sdt_var_expanding_visitor): Use lex_cast. (dwarf_builder::build): Copy probe and location for TOK_MARK cases. Call derive_probes for kprobe and utrace cases. --- tapsets.cxx | 230 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 115 insertions(+), 115 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index d8fe8f8e..b684adc2 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -663,19 +663,19 @@ struct dwarf_builder: public derived_probe_builder public: enum probe_types { - uprobe_type = 0x31425250, - kprobe_type = 0x32425250, - utrace_type = 0x33425250, + uprobe_type = 0x31425250, // "PRB1" + kprobe_type = 0x32425250, // "PRB2" + utrace_type = 0x33425250, // "PRB3" } probe_type; - bool have_probes; __uint64_t probe_arg; - string mark_name; + string & mark_name; string probe_name; - probe_table(systemtap_session & sess, dwflpp* dw, probe_point* location); + probe_table(string & mark_name, systemtap_session & sess, dwflpp * dw, probe_point * location); bool get_next_probe(); private: - systemtap_session sess; + bool have_probes; + systemtap_session & sess; dwflpp* dw; probe_point* location; Elf_Data *pdata; @@ -684,11 +684,12 @@ struct dwarf_builder: public derived_probe_builder }; }; -dwarf_builder::probe_table::probe_table(systemtap_session & sess, dwflpp* dw, probe_point* location) +dwarf_builder::probe_table::probe_table(string& mark_name, systemtap_session & sess, dwflpp* dw, probe_point* location): + mark_name(mark_name), sess(sess), dw(dw), location(location) { Elf* elf; GElf_Shdr shdr_mem; - GElf_Shdr *shdr = NULL; + GElf_Shdr *shdr; Dwarf_Addr bias; size_t shstrndx; @@ -698,12 +699,8 @@ dwarf_builder::probe_table::probe_table(systemtap_session & sess, dwflpp* dw, pr dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); - this->dw = dw; - this->sess = sess; - this->location = location; - this->mark_name = location->components[1]->arg->tok->content; have_probes = false; - + // Is there a .probes section? while ((probe_scn = elf_nextscn (elf, probe_scn))) { @@ -716,18 +713,14 @@ dwarf_builder::probe_table::probe_table(systemtap_session & sess, dwflpp* dw, pr break; } } - - if (!have_probes) - return; - + // Older versions put .probes section in the debuginfo dwarf file, // so check if it actually exists, if not take the main elf file - if (shdr->sh_type == SHT_NOBITS) + if (have_probes && shdr->sh_type == SHT_NOBITS) { elf = dwfl_module_getelf (dw->module, &bias); dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); probe_scn = NULL; - have_probes = false; while ((probe_scn = elf_nextscn (elf, probe_scn))) { shdr = gelf_getshdr (probe_scn, &shdr_mem); @@ -738,9 +731,6 @@ dwarf_builder::probe_table::probe_table(systemtap_session & sess, dwflpp* dw, pr } } - if (!have_probes) - return; - pdata = elf_getdata_rawchunk (elf, shdr->sh_offset, shdr->sh_size, ELF_T_BYTE); probe_scn_offset = 0; probe_scn_addr = shdr->sh_addr; @@ -755,14 +745,20 @@ dwarf_builder::probe_table::get_next_probe() { if (! have_probes) return false; - + // Extract probe info from the .probes section if (sess.verbose > 3) clog << "probe_type == use_uprobe, use statement addr" << endl; - + while (probe_scn_offset < pdata->d_size) { - probe_type = (enum probe_types)*((int*)((char*)pdata->d_buf + probe_scn_offset)); + struct probe_entry + { + __uint64_t name; + __uint64_t arg; + } *pbe; + __uint32_t *type = (__uint32_t*) ((char*)pdata->d_buf + probe_scn_offset); + probe_type = (enum probe_types)*type; if (probe_type != uprobe_type && probe_type != kprobe_type && probe_type != utrace_type) { @@ -772,28 +768,22 @@ dwarf_builder::probe_table::get_next_probe() if (sess.verbose > 5) clog << "got unknown probe_type: 0x" << hex << probe_type << dec << endl; - probe_scn_offset += sizeof(int); + probe_scn_offset += sizeof(__uint32_t); continue; } - probe_scn_offset += sizeof(int); - if (probe_scn_offset % (sizeof(__uint64_t))) - probe_scn_offset += sizeof(__uint64_t) - (probe_scn_offset % sizeof(__uint64_t)); - - probe_name = ((char*)((long)(pdata->d_buf) + (long)(*((long*)((char*)pdata->d_buf + probe_scn_offset)) - probe_scn_addr))); - probe_scn_offset += sizeof(void*); - if (probe_scn_offset % (sizeof(__uint64_t))) - probe_scn_offset += sizeof(__uint64_t) - (probe_scn_offset % sizeof(__uint64_t)); - probe_arg = *((__uint64_t*)((char*)pdata->d_buf + probe_scn_offset)); + probe_scn_offset += sizeof(__uint32_t); + probe_scn_offset += probe_scn_offset % sizeof(__uint64_t); + pbe = (struct probe_entry*) ((char*)pdata->d_buf + probe_scn_offset); + probe_name = (char*)((char*)pdata->d_buf + pbe->name - (char*)probe_scn_addr); + probe_arg = pbe->arg; if (sess.verbose > 4) clog << "saw .probes " << probe_name << "@0x" << hex << probe_arg << dec << endl; - - if (probe_scn_offset % (sizeof(__uint64_t)*2)) - probe_scn_offset = (probe_scn_offset + sizeof(__uint64_t)*2) - (probe_scn_offset % (sizeof(__uint64_t)*2)); - if ((strcmp (mark_name.c_str(), probe_name.c_str()) == 0) - || (dw->name_has_wildcard (mark_name.c_str()) - && dw->function_name_matches_pattern - (probe_name.c_str(), mark_name.c_str()))) + + probe_scn_offset += sizeof (struct probe_entry); + if ((mark_name == probe_name) + || (dw->name_has_wildcard (mark_name) + && dw->function_name_matches_pattern (probe_name, mark_name))) { if (sess.verbose > 3) clog << "found probe_name" << probe_name << " at 0x" @@ -2353,9 +2343,9 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e) saveme->chain = e->saved_conversion_error; e->saved_conversion_error = saveme; } - else + else { - // Upon user request for ignoring context, the symbol is replaced + // Upon user request for ignoring context, the symbol is replaced // with a literal 0 and a warning message displayed literal_number* ln_zero = new literal_number (0); ln_zero->tok = e->tok; @@ -3225,13 +3215,12 @@ sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) provide(e); return; } - + bool lvalue = is_active_lvalue(e); string argname = e->base_name.substr(1); functioncall *fc = new functioncall; - const char *argno_str = argname.substr(3).c_str(); - int argno = atoi(argno_str); // first arg is "hidden" probe name + int argno = lex_cast(argname.substr(3)); if (arg_count < 6) { @@ -3249,7 +3238,7 @@ sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) binary_expression *be = new binary_expression; be->tok = e->tok; functioncall *get_arg1 = new functioncall; - get_arg1->function = "ulong_arg"; + get_arg1->function = "pointer_arg"; get_arg1->tok = e->tok; literal_number* num = new literal_number(2); num->tok = e->tok; @@ -3261,34 +3250,31 @@ sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) be->right = inc; fc->args.push_back(be); } - + if (lvalue) *(target_symbol_setter_functioncalls.top()) = fc; + if (e->components.empty()) + { + provide(fc); + return; + } cast_op *cast = new cast_op; cast->base_name = "@cast"; cast->tok = e->tok; cast->operand = fc; cast->components = e->components; - char *arg_type; - if (asprintf (&arg_type, "%s_arg%d", probe_name.c_str(), argno) == -1) - return; - cast->type = arg_type; + cast->type = probe_name + "_arg" + lex_cast(argno); string sdt_include_path = ""; for (unsigned int i = 0; i < dw.sess.args.size(); i++) if (dw.sess.args[i].find("isdt=") == 0) sdt_include_path = dw.sess.args[i].substr(5); - if (asprintf (&arg_type, "<%s>", sdt_include_path.c_str()) == -1) - return; - cast->module = arg_type; + cast->module = "<" + sdt_include_path + ">"; dwarf_builder *db = new dwarf_builder(); dwarf_cast_expanding_visitor *v = new dwarf_cast_expanding_visitor(this->dw.sess, *db); v->visit_cast_op(cast); - if (cast->components.empty()) - provide(fc); - else - provide(cast); + provide(cast); } void @@ -3325,10 +3311,12 @@ dwarf_builder::build(systemtap_session & sess, if (((probe_point::component*)(location->components[1]))->functor == TOK_MARK) { - probe_table probe_table(sess, dw, location); + string mark_name; + assert (get_param(parameters, TOK_MARK, mark_name)); + probe_table probe_table(mark_name, sess, dw, location); if (! probe_table.get_next_probe()) return; - + if (sess.verbose > 3) clog << "TOK_MARK: " << probe_table.mark_name << endl; @@ -3336,22 +3324,31 @@ dwarf_builder::build(systemtap_session & sess, { do { - const token* sv_tok = location->components[1]->arg->tok; - location->components[1]->functor = TOK_STATEMENT; - location->components[1]->arg = new literal_number((long)probe_table.probe_arg); - location->components[1]->arg->tok = sv_tok; - ((literal_map_t&)parameters)[TOK_STATEMENT] = location->components[1]->arg; + probe *new_base = new probe; + *new_base = *base; + + new_base->body = deep_copy_visitor::deep_copy(base->body); + probe_point *new_location = new probe_point; + *new_location = *location; + new_base->locations.clear(); + + const token* sv_tok = new_location->components[1]->arg->tok; + new_location->components[1]->functor = TOK_STATEMENT; + new_location->components[1]->arg = new literal_number((long)probe_table.probe_arg); + new_location->components[1]->arg->tok = sv_tok; + ((literal_map_t&)parameters)[TOK_STATEMENT] = new_location->components[1]->arg; + new_base->locations.push_back(new_location); if (sess.verbose > 3) clog << "probe_type == use_uprobe, use statement addr: 0x" << hex << probe_table.probe_arg << dec << endl; - + // Now expand the local variables in the probe body sdt_var_expanding_visitor svv (*dw, probe_table.mark_name, probe_table.probe_arg, false); - base->body = svv.require (base->body); + new_base->body = svv.require (new_base->body); - dwarf_query q(sess, base, location, *dw, parameters, finished_results); + dwarf_query q(sess, new_base, new_location, *dw, parameters, finished_results); q.has_mark = true; dw->iterate_over_modules(&query_module, &q); if (sess.listing_mode) @@ -3368,28 +3365,36 @@ dwarf_builder::build(systemtap_session & sess, { do { - block *b = ((block*)(base->body)); + probe *new_base = new probe; + *new_base = *base; + + new_base->body = deep_copy_visitor::deep_copy(base->body); + probe_point *new_location = new probe_point; + *new_location = *location; + new_base->locations.clear(); + + block *b = ((block*)(new_base->body)); functioncall *fc = new functioncall; fc->function = "ulong_arg"; - fc->tok = base->body->tok; + fc->tok = new_base->body->tok; literal_number* num = new literal_number(1); - num->tok = base->body->tok; + num->tok = new_base->body->tok; fc->args.push_back(num); functioncall *fcus = new functioncall; fcus->function = "user_string"; fcus->type = pe_string; - fcus->tok = base->body->tok; + fcus->tok = new_base->body->tok; fcus->args.push_back(fc); // Generate: if (arg1 != mark("label")) next; if_statement *is = new if_statement; is->thenblock = new next_statement; is->elseblock = NULL; - is->tok = base->body->tok; + is->tok = new_base->body->tok; comparison *be = new comparison; be->op = "!="; - be->tok = base->body->tok; + be->tok = new_base->body->tok; be->left = fcus; be->right = new literal_string(probe_table.mark_name); is->condition = be; @@ -3398,22 +3403,14 @@ dwarf_builder::build(systemtap_session & sess, // Now expand the local variables in the probe body sdt_var_expanding_visitor svv (*dw, probe_table.mark_name, probe_table.probe_arg, true); - base->body = svv.require (base->body); - location->components[0]->functor = "kernel"; - location->components[0]->arg = NULL; - location->components[1]->functor = "function"; - location->components[1]->arg = new literal_string("*getegid*"); - ((literal_map_t&)parameters).erase(TOK_PROCESS); - ((literal_map_t&)parameters).erase(TOK_MARK); - ((literal_map_t&)parameters).insert(pair("kernel", NULL)); - ((literal_map_t&)parameters).insert(pair("function", location->components[1]->arg)); - - dw = get_kern_dw(sess); - - dwarf_query q(sess, base, location, *dw, parameters, finished_results); - q.has_mark = true; - - dw->iterate_over_modules(&query_module, &q); + new_base->body = svv.require (new_base->body); + new_location->components[0]->functor = "kernel"; + new_location->components[0]->arg = NULL; + new_location->components[1]->functor = "function"; + new_location->components[1]->arg = new literal_string("*getegid*"); + new_base->locations.push_back(new_location); + + derive_probes(sess, new_base, finished_results); } while (probe_table.get_next_probe()); return; @@ -3423,48 +3420,56 @@ dwarf_builder::build(systemtap_session & sess, { do { - block *b = ((block*)(base->body)); + probe *new_base = new probe; + *new_base = *base; + + new_base->body = deep_copy_visitor::deep_copy(base->body); + probe_point *new_location = new probe_point; + *new_location = *location; + new_base->locations.clear(); + + block *b = ((block*)(new_base->body)); // Generate: if ($syscall != 0xbead) next; if_statement *issc = new if_statement; issc->thenblock = new next_statement; issc->elseblock = NULL; - issc->tok = base->body->tok; + issc->tok = new_base->body->tok; comparison *besc = new comparison; besc->op = "!="; - besc->tok = base->body->tok; + besc->tok = new_base->body->tok; functioncall* n = new functioncall; - n->tok = base->body->tok; + n->tok = new_base->body->tok; n->function = "_utrace_syscall_nr"; n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session besc->left = n; literal_number* fake_syscall = new literal_number(0xbead); - fake_syscall->tok = base->body->tok; + fake_syscall->tok = new_base->body->tok; besc->right = fake_syscall; issc->condition = besc; b->statements.insert(b->statements.begin(),(statement*) issc); functioncall *fc = new functioncall; fc->function = "ulong_arg"; - fc->tok = base->body->tok; + fc->tok = new_base->body->tok; literal_number* num = new literal_number(1); - num->tok = base->body->tok; + num->tok = new_base->body->tok; fc->args.push_back(num); functioncall *fcus = new functioncall; fcus->function = "user_string"; fcus->type = pe_string; - fcus->tok = base->body->tok; + fcus->tok = new_base->body->tok; fcus->args.push_back(fc); // Generate: if (arg1 != mark("label")) next; if_statement *is = new if_statement; is->thenblock = new next_statement; is->elseblock = NULL; - is->tok = base->body->tok; + is->tok = new_base->body->tok; comparison *be = new comparison; be->op = "!="; - be->tok = base->body->tok; + be->tok = new_base->body->tok; be->left = fcus; be->right = new literal_string(probe_table.mark_name); is->condition = be; @@ -3473,19 +3478,14 @@ dwarf_builder::build(systemtap_session & sess, // Now expand the local variables in the probe body sdt_var_expanding_visitor svv (*dw, probe_table.mark_name, probe_table.probe_arg, true); - base->body = svv.require (base->body); + new_base->body = svv.require (new_base->body); // process("executable").syscall - location->components[1]->functor = "syscall"; - location->components[1]->arg = NULL; - ((literal_map_t&)parameters).erase(TOK_MARK); - ((literal_map_t&)parameters).insert(pair("syscall", NULL)); - - // XXX: duplicates code above - if (! kern_dw) - dw = get_kern_dw(sess); + new_location->components[1]->functor = "syscall"; + new_location->components[1]->arg = NULL; + new_base->locations.push_back(new_location); - derive_probes(sess, base, finished_results); + derive_probes(sess, new_base, finished_results); } while (probe_table.get_next_probe()); return; @@ -3508,7 +3508,7 @@ dwarf_builder::build(systemtap_session & sess, dw->module = 0; } - + dwarf_query q(sess, base, location, *dw, parameters, finished_results); @@ -5427,7 +5427,7 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s) } s.op->line() << ") {"; s.op->indent(1); - common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", lex_cast_qstring (*p->sole_location())); s.op->newline() << "c->marker_name = " << lex_cast_qstring (p->tracepoint_name) -- cgit From 5e8208c0c3012c3f2b0215385c2b02422c2e4769 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 9 Jun 2009 08:54:59 -0700 Subject: Fix uninitialized shdr in probe_table (redo commit 3d022fa9c6bdbca383dfc639d08d65287c708f56) * tapsets.cxx (dwarf_builder::probe_table::probe_table): gcc 4.4 complains that shdr may be used uninitialized. I added returns to ensure that it's ok, but gcc still complains. Set the thing to NULL as well to silence the beast. --- tapsets.cxx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index b684adc2..4b8d9a13 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -689,7 +689,7 @@ dwarf_builder::probe_table::probe_table(string& mark_name, systemtap_session & s { Elf* elf; GElf_Shdr shdr_mem; - GElf_Shdr *shdr; + GElf_Shdr *shdr = NULL; Dwarf_Addr bias; size_t shstrndx; @@ -713,6 +713,9 @@ dwarf_builder::probe_table::probe_table(string& mark_name, systemtap_session & s break; } } + + if (!have_probes) + return; // Older versions put .probes section in the debuginfo dwarf file, // so check if it actually exists, if not take the main elf file @@ -721,6 +724,7 @@ dwarf_builder::probe_table::probe_table(string& mark_name, systemtap_session & s elf = dwfl_module_getelf (dw->module, &bias); dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx)); probe_scn = NULL; + have_probes = false; while ((probe_scn = elf_nextscn (elf, probe_scn))) { shdr = gelf_getshdr (probe_scn, &shdr_mem); @@ -731,6 +735,9 @@ dwarf_builder::probe_table::probe_table(string& mark_name, systemtap_session & s } } + if (!have_probes) + return; + pdata = elf_getdata_rawchunk (elf, shdr->sh_offset, shdr->sh_size, ELF_T_BYTE); probe_scn_offset = 0; probe_scn_addr = shdr->sh_addr; -- cgit From 56e33af59ec3003a1559a052fb1936647c01580c Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Tue, 9 Jun 2009 17:05:53 -0400 Subject: * tapsets.cxx (sdt_var_expanding_visitor::process_name): New. (sdt_var_expanding_visitor::visit_target_symbol): Have @cast use types from a dtrace built object instead of a dtrace supplied header. (dwarf_builder::build): Use it. --- tapsets.cxx | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 4b8d9a13..4aae1aa6 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3195,12 +3195,13 @@ dwarf_derived_probe_group::emit_module_exit (systemtap_session& s) struct sdt_var_expanding_visitor: public var_expanding_visitor { - sdt_var_expanding_visitor(dwflpp& dw, string& probe_name, + sdt_var_expanding_visitor(dwflpp& dw, string & process_name, string & probe_name, int arg_count, bool have_reg_args): - dw (dw), probe_name (probe_name), have_reg_args (have_reg_args), - arg_count (arg_count) {} - dwflpp& dw; - string probe_name; + dw (dw), process_name (process_name), probe_name (probe_name), + have_reg_args (have_reg_args), arg_count (arg_count) {} + dwflpp & dw; + string & process_name; + string & probe_name; bool have_reg_args; int arg_count; @@ -3272,11 +3273,7 @@ sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) cast->operand = fc; cast->components = e->components; cast->type = probe_name + "_arg" + lex_cast(argno); - string sdt_include_path = ""; - for (unsigned int i = 0; i < dw.sess.args.size(); i++) - if (dw.sess.args[i].find("isdt=") == 0) - sdt_include_path = dw.sess.args[i].substr(5); - cast->module = "<" + sdt_include_path + ">"; + cast->module = process_name; dwarf_builder *db = new dwarf_builder(); dwarf_cast_expanding_visitor *v = new dwarf_cast_expanding_visitor(this->dw.sess, *db); v->visit_cast_op(cast); @@ -3320,6 +3317,8 @@ dwarf_builder::build(systemtap_session & sess, { string mark_name; assert (get_param(parameters, TOK_MARK, mark_name)); + string process_name; + assert (get_param(parameters, TOK_PROCESS, process_name)); probe_table probe_table(mark_name, sess, dw, location); if (! probe_table.get_next_probe()) return; @@ -3351,7 +3350,7 @@ dwarf_builder::build(systemtap_session & sess, << hex << probe_table.probe_arg << dec << endl; // Now expand the local variables in the probe body - sdt_var_expanding_visitor svv (*dw, probe_table.mark_name, + sdt_var_expanding_visitor svv (*dw, process_name, probe_table.mark_name, probe_table.probe_arg, false); new_base->body = svv.require (new_base->body); @@ -3408,7 +3407,7 @@ dwarf_builder::build(systemtap_session & sess, b->statements.insert(b->statements.begin(),(statement*) is); // Now expand the local variables in the probe body - sdt_var_expanding_visitor svv (*dw, probe_table.mark_name, + sdt_var_expanding_visitor svv (*dw, process_name, probe_table.mark_name, probe_table.probe_arg, true); new_base->body = svv.require (new_base->body); new_location->components[0]->functor = "kernel"; @@ -3483,7 +3482,7 @@ dwarf_builder::build(systemtap_session & sess, b->statements.insert(b->statements.begin(),(statement*) is); // Now expand the local variables in the probe body - sdt_var_expanding_visitor svv (*dw, probe_table.mark_name, + sdt_var_expanding_visitor svv (*dw, process_name, probe_table.mark_name, probe_table.probe_arg, true); new_base->body = svv.require (new_base->body); -- cgit From 3e1e31fbbbd19b9175b2fd0ed74e5e0dc7ba2673 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 9 Jun 2009 16:34:38 -0700 Subject: Simplify process.mark parameter parsing This just makes it so the parameters only need to be checked and pulled out once. --- tapsets.cxx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 4aae1aa6..9ded301d 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3313,12 +3313,9 @@ dwarf_builder::build(systemtap_session & sess, if (sess.verbose > 3) clog << "dwarf_builder::build for " << module_name << endl; - if (((probe_point::component*)(location->components[1]))->functor == TOK_MARK) + string mark_name; + if (get_param(parameters, TOK_MARK, mark_name)) { - string mark_name; - assert (get_param(parameters, TOK_MARK, mark_name)); - string process_name; - assert (get_param(parameters, TOK_PROCESS, process_name)); probe_table probe_table(mark_name, sess, dw, location); if (! probe_table.get_next_probe()) return; @@ -3350,7 +3347,7 @@ dwarf_builder::build(systemtap_session & sess, << hex << probe_table.probe_arg << dec << endl; // Now expand the local variables in the probe body - sdt_var_expanding_visitor svv (*dw, process_name, probe_table.mark_name, + sdt_var_expanding_visitor svv (*dw, module_name, probe_table.mark_name, probe_table.probe_arg, false); new_base->body = svv.require (new_base->body); @@ -3407,7 +3404,7 @@ dwarf_builder::build(systemtap_session & sess, b->statements.insert(b->statements.begin(),(statement*) is); // Now expand the local variables in the probe body - sdt_var_expanding_visitor svv (*dw, process_name, probe_table.mark_name, + sdt_var_expanding_visitor svv (*dw, module_name, probe_table.mark_name, probe_table.probe_arg, true); new_base->body = svv.require (new_base->body); new_location->components[0]->functor = "kernel"; @@ -3482,7 +3479,7 @@ dwarf_builder::build(systemtap_session & sess, b->statements.insert(b->statements.begin(),(statement*) is); // Now expand the local variables in the probe body - sdt_var_expanding_visitor svv (*dw, process_name, probe_table.mark_name, + sdt_var_expanding_visitor svv (*dw, module_name, probe_table.mark_name, probe_table.probe_arg, true); new_base->body = svv.require (new_base->body); -- cgit From 18247b09c99a85b7600abfca48a21818a78a9e97 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 9 Jun 2009 16:37:14 -0700 Subject: Remove the spurious sdt @cast expansion The result of sdt's private @cast expansion was not being used, and it's not really needed anyway. The global cast visitor is registered to run as a post-processing step on ALL functions and probes, and so it will pick up and expand sdt's casts too. --- tapsets.cxx | 3 --- 1 file changed, 3 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 9ded301d..71456ab6 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3274,9 +3274,6 @@ sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) cast->components = e->components; cast->type = probe_name + "_arg" + lex_cast(argno); cast->module = process_name; - dwarf_builder *db = new dwarf_builder(); - dwarf_cast_expanding_visitor *v = new dwarf_cast_expanding_visitor(this->dw.sess, *db); - v->visit_cast_op(cast); provide(cast); } -- cgit From 9f02b156fd0b57a57f8d4985cdd2902a6ee920cb Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 9 Jun 2009 16:41:30 -0700 Subject: Remove sdt_var_expanding_visitor's now-unused dw --- tapsets.cxx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 71456ab6..61962b3d 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3195,11 +3195,10 @@ dwarf_derived_probe_group::emit_module_exit (systemtap_session& s) struct sdt_var_expanding_visitor: public var_expanding_visitor { - sdt_var_expanding_visitor(dwflpp& dw, string & process_name, string & probe_name, + sdt_var_expanding_visitor(string & process_name, string & probe_name, int arg_count, bool have_reg_args): - dw (dw), process_name (process_name), probe_name (probe_name), + process_name (process_name), probe_name (probe_name), have_reg_args (have_reg_args), arg_count (arg_count) {} - dwflpp & dw; string & process_name; string & probe_name; bool have_reg_args; @@ -3344,7 +3343,7 @@ dwarf_builder::build(systemtap_session & sess, << hex << probe_table.probe_arg << dec << endl; // Now expand the local variables in the probe body - sdt_var_expanding_visitor svv (*dw, module_name, probe_table.mark_name, + sdt_var_expanding_visitor svv (module_name, probe_table.mark_name, probe_table.probe_arg, false); new_base->body = svv.require (new_base->body); @@ -3401,7 +3400,7 @@ dwarf_builder::build(systemtap_session & sess, b->statements.insert(b->statements.begin(),(statement*) is); // Now expand the local variables in the probe body - sdt_var_expanding_visitor svv (*dw, module_name, probe_table.mark_name, + sdt_var_expanding_visitor svv (module_name, probe_table.mark_name, probe_table.probe_arg, true); new_base->body = svv.require (new_base->body); new_location->components[0]->functor = "kernel"; @@ -3476,7 +3475,7 @@ dwarf_builder::build(systemtap_session & sess, b->statements.insert(b->statements.begin(),(statement*) is); // Now expand the local variables in the probe body - sdt_var_expanding_visitor svv (*dw, module_name, probe_table.mark_name, + sdt_var_expanding_visitor svv (module_name, probe_table.mark_name, probe_table.probe_arg, true); new_base->body = svv.require (new_base->body); -- cgit From 59d00eb0920ca89f67704e0f0bf0aa3074abb328 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 9 Jun 2009 16:47:17 -0700 Subject: Remove probe_table's unused location member --- tapsets.cxx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 61962b3d..64657454 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -670,22 +670,21 @@ struct dwarf_builder: public derived_probe_builder __uint64_t probe_arg; string & mark_name; string probe_name; - probe_table(string & mark_name, systemtap_session & sess, dwflpp * dw, probe_point * location); + probe_table(string & mark_name, systemtap_session & sess, dwflpp * dw); bool get_next_probe(); private: bool have_probes; systemtap_session & sess; dwflpp* dw; - probe_point* location; Elf_Data *pdata; size_t probe_scn_offset; size_t probe_scn_addr; }; }; -dwarf_builder::probe_table::probe_table(string& mark_name, systemtap_session & sess, dwflpp* dw, probe_point* location): - mark_name(mark_name), sess(sess), dw(dw), location(location) +dwarf_builder::probe_table::probe_table(string& mark_name, systemtap_session & sess, dwflpp* dw): + mark_name(mark_name), sess(sess), dw(dw) { Elf* elf; GElf_Shdr shdr_mem; @@ -3312,7 +3311,7 @@ dwarf_builder::build(systemtap_session & sess, string mark_name; if (get_param(parameters, TOK_MARK, mark_name)) { - probe_table probe_table(mark_name, sess, dw, location); + probe_table probe_table(mark_name, sess, dw); if (! probe_table.get_next_probe()) return; -- cgit From a8ec77194e89a8e685c7f44260be75a632254eaa Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 9 Jun 2009 17:04:40 -0700 Subject: Add bounds-checking to sdt $argN --- tapsets.cxx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'tapsets.cxx') diff --git a/tapsets.cxx b/tapsets.cxx index 64657454..3ecf2250 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3197,7 +3197,10 @@ struct sdt_var_expanding_visitor: public var_expanding_visitor sdt_var_expanding_visitor(string & process_name, string & probe_name, int arg_count, bool have_reg_args): process_name (process_name), probe_name (probe_name), - have_reg_args (have_reg_args), arg_count (arg_count) {} + have_reg_args (have_reg_args), arg_count (arg_count) + { + assert(!have_reg_args || (arg_count >= 0 && arg_count <= 10)); + } string & process_name; string & probe_name; bool have_reg_args; @@ -3221,13 +3224,14 @@ sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) provide(e); return; } - + + int argno = lex_cast(e->base_name.substr(4)); + if (argno < 1 || argno > arg_count) + throw semantic_error ("invalid argument number", e->tok); + bool lvalue = is_active_lvalue(e); - string argname = e->base_name.substr(1); functioncall *fc = new functioncall; - int argno = lex_cast(argname.substr(3)); - if (arg_count < 6) { fc->function = "ulong_arg"; -- cgit