summaryrefslogtreecommitdiffstats
path: root/tapsets.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'tapsets.cxx')
-rw-r--r--tapsets.cxx3327
1 files changed, 534 insertions, 2793 deletions
diff --git a/tapsets.cxx b/tapsets.cxx
index d7e9ab4f..3ecf2250 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>
@@ -47,7 +43,6 @@ extern "C" {
#include <dwarf.h>
#include <elf.h>
#include <obstack.h>
-#include <regex.h>
#include <glob.h>
#include <fnmatch.h>
#include <stdio.h>
@@ -250,19 +245,21 @@ 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);
// Can we handle this query with just symbol-table info?
enum dbinfo_reqt
@@ -273,67 +270,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 +278,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 +315,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,1834 +324,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)
- :
- 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)
- {
- }
-
-
- // 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(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
@@ -2511,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;
@@ -2575,270 +600,25 @@ 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;
map <string,dwflpp*> 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)
@@ -2877,8 +657,150 @@ struct dwarf_builder: public derived_probe_builder
probe_point * location,
literal_map_t const & parameters,
vector<derived_probe *> & finished_results);
+
+ struct probe_table
+ {
+ public:
+ enum probe_types
+ {
+ uprobe_type = 0x31425250, // "PRB1"
+ kprobe_type = 0x32425250, // "PRB2"
+ utrace_type = 0x33425250, // "PRB3"
+ } probe_type;
+ __uint64_t probe_arg;
+ string & mark_name;
+ string probe_name;
+ probe_table(string & mark_name, systemtap_session & sess, dwflpp * dw);
+ bool get_next_probe();
+
+ private:
+ bool have_probes;
+ systemtap_session & sess;
+ dwflpp* dw;
+ 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):
+ mark_name(mark_name), sess(sess), dw(dw)
+{
+ Elf* elf;
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = NULL;
+ 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));
+
+ 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;
+ }
+ }
+
+ 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)
+ {
+ 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);
+ if (strcmp (elf_strptr (elf, shstrndx, shdr->sh_name),
+ ".probes") == 0)
+ have_probes = true;
+ break;
+ }
+ }
+
+ 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;
+ 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)
+ {
+ 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)
+ {
+ // 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(__uint32_t);
+ continue;
+ }
+ 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;
+
+ 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"
+ << hex << probe_arg << dec << endl;
+ return true;
+ }
+ else
+ continue;
+ }
+ return false;
+}
dwarf_query::dwarf_query(systemtap_session & sess,
probe * base_probe,
@@ -2911,12 +833,35 @@ 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;
}
+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()
{
@@ -2935,7 +880,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_module_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
{
@@ -3052,138 +999,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)
{
@@ -3274,129 +1089,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,
@@ -3405,40 +1097,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)
{
@@ -3454,7 +1119,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;
@@ -3646,7 +1312,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
@@ -3896,7 +1563,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)
@@ -3955,26 +1623,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)
{
@@ -4124,13 +1772,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);
@@ -4158,7 +1806,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;
@@ -4170,12 +1818,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
{
@@ -4924,54 +2566,27 @@ 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);
+ dw->iterate_over_modules(&query_module, &q);
}
if (code.empty())
@@ -5314,6 +2929,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;";
@@ -5374,6 +2990,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 << "\",";
@@ -5477,8 +3095,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) << "}";
@@ -5573,6 +3192,93 @@ 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(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)
+ {
+ assert(!have_reg_args || (arg_count >= 0 && arg_count <= 10));
+ }
+ string & process_name;
+ 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;
+ }
+
+ int argno = lex_cast<int>(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);
+ functioncall *fc = new functioncall;
+
+ 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 = "pointer_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;
+
+ 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;
+ cast->type = probe_name + "_arg" + lex_cast<string>(argno);
+ cast->module = process_name;
+
+ provide(cast);
+}
void
dwarf_builder::build(systemtap_session & sess,
@@ -5592,13 +3298,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,172 +3306,210 @@ 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)
clog << "dwarf_builder::build for " << module_name << endl;
- if (((probe_point::component*)(location->components[1]))->functor == TOK_MARK)
- {
- enum probe_types
+ string mark_name;
+ if (get_param(parameters, TOK_MARK, mark_name))
{
- 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(mark_name, sess, dw);
+ 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
+ {
+ 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;
- dwarf_query q(sess, base, location, *dw, parameters, finished_results);
- q.has_mark = true;
- dw->query_modules(&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 (module_name, probe_table.mark_name,
+ probe_table.probe_arg, false);
+ new_base->body = svv.require (new_base->body);
+
+ 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)
+ {
+ 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<string,literal*>(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
+ {
+ 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 = new_base->body->tok;
+ literal_number* num = new literal_number(1);
+ 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 = 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 = new_base->body->tok;
+ comparison *be = new comparison;
+ be->op = "!=";
+ be->tok = new_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 (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";
+ 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;
+ }
- else if (sess.verbose > 3)
- clog << "probe_type == probes_no_dwarf" << endl;
+ else if (probe_table.probe_type == probe_table.utrace_type)
+ {
+ do
+ {
+ 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 = new_base->body->tok;
+ comparison *besc = new comparison;
+ besc->op = "!=";
+ besc->tok = new_base->body->tok;
+ functioncall* n = new functioncall;
+ 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 = 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 = new_base->body->tok;
+ literal_number* num = new literal_number(1);
+ 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 = 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 = new_base->body->tok;
+ comparison *be = new comparison;
+ be->op = "!=";
+ be->tok = new_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 (module_name, probe_table.mark_name,
+ probe_table.probe_arg, true);
+ new_base->body = svv.require (new_base->body);
+
+ // process("executable").syscall
+ new_location->components[1]->functor = "syscall";
+ new_location->components[1]->arg = NULL;
+ new_base->locations.push_back(new_location);
+
+ derive_probes(sess, new_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<string,literal*>(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);
@@ -5799,7 +3537,7 @@ dwarf_builder::build(systemtap_session & sess,
return;
}
- dw->query_modules(&q);
+ dw->iterate_over_modules(&query_module, &q);
}
symbol_table::~symbol_table()
@@ -6686,7 +4424,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
{
@@ -6820,7 +4558,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.
@@ -6836,6 +4574,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;";
@@ -6882,6 +4621,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
@@ -6991,8 +4733,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) << "}";
@@ -7011,27 +4754,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";
@@ -7902,8 +5645,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;
}
@@ -7928,8 +5670,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;
}
@@ -7947,7 +5688,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);
}