diff options
Diffstat (limited to 'tapsets.cxx')
-rw-r--r-- | tapsets.cxx | 2267 |
1 files changed, 31 insertions, 2236 deletions
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 <cstdlib> #include <algorithm> #include <deque> #include <iostream> #include <map> -#ifdef HAVE_TR1_UNORDERED_MAP -#include <tr1/unordered_map> -#else -#include <ext/hash_map> -#endif #include <set> #include <sstream> #include <stdexcept> @@ -273,67 +269,6 @@ enum dbinfo_reqt 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; @@ -342,57 +277,6 @@ 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<string, module_info*> 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<string,Dwarf_Die> cu_function_cache_t; -typedef tr1::unordered_map<string,cu_function_cache_t*> 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<const char*> h; return h(s.c_str()); } -}; - -typedef hash_map<string,Dwarf_Die,stringhash> cu_function_cache_t; -typedef hash_map<string,cu_function_cache_t*,stringhash> mod_cu_function_cache_t; // module:cu -> function -> die -#endif - -struct symbol_table { module_info *mod_info; // associated module @@ -430,25 +314,6 @@ static bool null_die(Dwarf_Die *die) 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_info> inline_instance_map_t; -typedef vector<func_info> func_info_map_t; - // PR 9941 introduces the need for a predicate @@ -458,1838 +323,6 @@ int dwfl_report_offline_predicate (const char* modname, const char* filename) 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<Dwarf*, vector<Dwarf_Die>*> 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<Dwarf_Die>* v = module_cu_cache[dw]; - if (v == 0) - { - v = new vector<Dwarf_Die>; - 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<string, vector<Dwarf_Die>*> 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<Dwarf_Die>* v = static_cast<vector<Dwarf_Die>*>(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<Dwarf_Die>* v = cu_inl_function_cache[key]; - if (v == 0) - { - v = new vector<Dwarf_Die>; - cu_inl_function_cache[key] = v; - dwarf_func_inline_instances (function, cu_inl_function_caching_callback, v); - } - - 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; - } - } - - - // ----------------------------------------------------------------- - - /* 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<cu_function_cache_t*>(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<cu_function_cache_t*>(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<dwarf_query *>(data); - int lineno = lines[0]; - auto_free_ref<Dwarf_Line**> 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<int> lines_probed; - pair<set<int>::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<char const *> & 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<string>(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<string>(pc) - + ((scope_die == NULL) ? "" - : (string (" in ") - + (dwarf_diename(scope_die) ?: "<unknown>") - + "(" + (dwarf_diename(cu) ?: "<unknown>") - + ")")) - + " 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<string>(pc) - + ((scope_die == NULL) ? "" - : (string (" in ") - + (dwarf_diename(scope_die) ?: "<unknown>") - + "(" + (dwarf_diename(cu) ?: "<unknown>") - + ")")) - + (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) ?: "<anonymous>") - << " 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) ?: "<anonymous>") - << " is empty"; - break; - - case -1: // Error. - default: // Shouldn't happen. - o << ((typetag == DW_TAG_union_type) ? " union " : " struct ") - << (dwarf_diename_integrate (die) ?: "<anonymous>") - << ": " << 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)?:"<anonymous>"); - return; - } - - if (!dwarf_formref_die (&temp_attr, &temp_die)) - { - clog << "\n Error in decoding type attribute for " - << (dwarf_diename(&temp_die)?:"<anonymous>"); - 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<Dwarf_Attribute>& 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) ?: "<anonymous>") - + 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<Dwarf_Word>(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) ?: "<anonymous>"), - e->tok); - *die_mem = *tmpdie; - } - - { - vector<Dwarf_Attribute> 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) ?: "<unknown>") - + 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) ?: "<anonymous type>"), - e->tok); - break; - case DW_TAG_base_type: - throw semantic_error ("field '" - + e->components[i].second - + "' vs. base type " - + string(dwarf_diename_integrate (die) ?: "<anonymous type>"), - 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) ?: "<anonymous type>") - + ": unexpected type tag " - + lex_cast<string>(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 : "<unknown>"; - throw semantic_error ("unsupported type tag " - + lex_cast<string>(typetag) - + " for " + diestr, e->tok); - break; - - case DW_TAG_structure_type: - case DW_TAG_union_type: - dname = dwarf_diename(die); - diestr = (dname != NULL) ? dname : "<unknown>"; - 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 : "<unknown>"; - - 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<string>(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<string>(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; - } - } - - string - express_as_string (string prelude, - string postlude, - struct location *head) - { - size_t bufsz = 1024; - char *buf = static_cast<char*>(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; - } - - 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; - - fb_attr = find_variable_and_frame_base (scope_die, pc, local, e, - &vardie, &fb_attr_mem); - - if (sess.verbose>2) - clog << "finding location for local '" << local - << "' near address 0x" << hex << pc - << ", module bias 0x" << module_bias << dec - << "\n"; - - 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<string>(dwarf_dieoffset (&vardie)) - + ")", - e->tok); - } - -#define obstack_chunk_alloc malloc -#define obstack_chunk_free free - - struct obstack pool; - obstack_init (&pool); - struct location *tail = NULL; - - /* Given $foo->bar->baz[NN], translate the location of foo. */ - - struct location *head = translate_location (&pool, - &attr_mem, pc, fb_attr, &tail, - e); - - 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); - - /* Translate the assignment part, either - x = $foo->bar->baz[NN] - or - $foo->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); - } - - - 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) ?: "<unknown>") - << "(" - << (dwarf_diename(cu) ?: "<unknown>") - << ")\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) ?: "<unknown>") - + "(" + string(dwarf_diename(cu) ?: "<unknown>") - + ")", - 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) ?: "<unknown>") - + "(" + string(dwarf_diename(cu) ?: "<unknown>") - + ") 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) ?: "<unknown>") - + "(" + string(dwarf_diename(cu) ?: "<unknown>") - + ")", - 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); - } - - - 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) ?: "<unknown>") - << "(" - << (dwarf_diename(cu) ?: "<unknown>") - << ")\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); - } - - - ~dwflpp() - { - if (dwfl) - dwfl_end(dwfl); - } -}; - - enum function_spec_type @@ -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<dwarf_query *>(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<dwarf_query *>(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<char const *>::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 { |