diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | main.cxx | 8 | ||||
-rw-r--r-- | staptree.h | 1 | ||||
-rw-r--r-- | tapsets.cxx | 911 |
5 files changed, 900 insertions, 35 deletions
@@ -1,3 +1,15 @@ +2005-06-20 Graydon Hoare <graydon@redhat.com> + + * configure.ac: Scan for libdwfl. + * staptree.h (verbose): New global. + * main.cxx (usage, main): Implement -v option. + * tapsets.cxx (dwflpp): New struct. + (query_statement): New function. + (query_function): New function. + (query_cu): New function. + (query_module): New function. + (dwarf_derived_probe): Implement primary forms. + 2005-06-14 Graydon Hoare <graydon@redhat.com> * tapsets.h: New file. diff --git a/configure.ac b/configure.ac index 31b5f745..ee75b2c6 100644 --- a/configure.ac +++ b/configure.ac @@ -23,9 +23,10 @@ AC_SUBST(CFLAGS) AC_SUBST(CXXFLAGS) dnl Need elfutils 0.102+ from <drepper@redhat.com> -AC_CHECK_HEADERS([libelf.h elfutils/libdw.h]) +AC_CHECK_HEADERS([libelf.h elfutils/libdw.h elfutils/libdwfl.h]) AC_CHECK_LIB(dw, dwarf_begin) AC_CHECK_LIB(elf, elf_begin) +AC_CHECK_LIB(dwfl, dwfl_begin) dnl Plop in the build (configure) date date=`date +%Y-%m-%d` @@ -23,6 +23,7 @@ extern "C" { using namespace std; +bool verbose = false; void usage () { @@ -37,6 +38,7 @@ void usage () cerr << endl; cerr << "Arguments:" << endl; cerr << " -- No more options after this" << endl; + cerr << " -v verbose" << endl; cerr << " -p NUM Stop after pass NUM 1-3" << endl; cerr << " (parse, elaborate, translate)" << endl; cerr << " -I DIR Look in DIR for additional .stp script files." << endl; @@ -61,11 +63,15 @@ main (int argc, char * const argv []) vector<string> args; // ARGS while (true) { - int grc = getopt (argc, argv, "p:I:e:o:"); + int grc = getopt (argc, argv, "vp:I:e:o:"); if (grc < 0) break; switch (grc) { + case 'v': + verbose = true; + break; + case 'p': last_pass = atoi (optarg); if (last_pass < 1 || last_pass > 3) @@ -14,6 +14,7 @@ #include <iostream> #include <stdexcept> +extern bool verbose; struct token; // parse.h struct semantic_error: public std::runtime_error diff --git a/tapsets.cxx b/tapsets.cxx index a57dccd5..cb4f68ea 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -11,15 +11,23 @@ #include "elaborate.h" #include "tapsets.h" #include "translate.h" + +#include <deque> #include <iostream> +#include <map> #include <sstream> -#include <deque> +#include <stdexcept> #include <vector> -#include <map> + +extern "C" { +#include <elfutils/libdwfl.h> +} + +#include <fnmatch.h> using namespace std; -// match_key +// Members of match_key. match_key::match_key(string const & n) : name(n), @@ -78,7 +86,7 @@ match_key::operator<(match_key const & other) const } -// match_node +// Members of match_node. match_node::match_node() : end(NULL) @@ -129,13 +137,13 @@ match_node::find_builder(vector<probe_point::component *> const & components, assert(pos <= components.size()); if (pos == components.size()) { - // probe_point ends here. we match iff we have - // an "end" entry here. if we don't, it'll be null. + // Probe_point ends here. We match iff we have + // an "end" entry here. If we don't, it'll be null. return end; } else { - // probe_point contains a component here. we match iff there's + // Probe_point contains a component here. We match iff there's // an entry in the sub table, and its value matches the rest // of the probe_point. match_key k(*components[pos]); @@ -151,6 +159,12 @@ match_node::find_builder(vector<probe_point::component *> const & components, parameters.push_back(make_pair(components[pos]->functor, components[pos]->arg)); } + else + { + // store a "null parameter" for any component we run into, anyways + literal_string *empty = NULL; + parameters.push_back(make_pair(components[pos]->functor, empty)); + } builder = i->second->find_builder(components, pos+1, parameters); if (k.have_parameter && !builder) parameters.pop_back(); @@ -184,13 +198,11 @@ alias_derived_probe void emit_probe_entries (translator_output* o, unsigned i) {} }; - -// the root of the global pattern-matching tree +// The root of the global pattern-matching tree. static match_node * root_node; -// the match-and-expand loop - +// The match-and-expand loop. void symresolution_info::derive_probes (probe *p, vector<derived_probe*>& dps) { @@ -223,7 +235,7 @@ symresolution_info::derive_probes (probe *p, vector<derived_probe*>& dps) derived_probe *derived = builder->build(p, loc, param_map); assert(derived); - // append to worklist if it's an alias; append to result otherwise + // Append to worklist if it's an alias; append to result otherwise. alias_derived_probe *as_alias = dynamic_cast<alias_derived_probe *>(derived); if (as_alias) { @@ -320,19 +332,430 @@ be_derived_probe::emit_probe_entries (translator_output* o, unsigned j) // ------------------------------------------------------------------------ -// dwarf derived probes XXX: todo dwfl integration +// Dwarf derived probes. // ------------------------------------------------------------------------ -struct dwarf_derived_probe: public derived_probe + +// Helper for dealing with selected portions of libdwfl in a more readable +// fashion, and with specific cleanup / checking / logging options. + +struct +dwflpp +{ + + Dwfl * dwfl; + + // These are "current" values we focus on. + Dwfl_Module * module; + Dwarf * module_dwarf; + Dwarf_Addr module_bias; + Dwarf_Die * cu; + Dwarf_Func * function; + + string module_name; + string cu_name; + string function_name; + + string const default_name(char const * in, + char const * type) + { + if (in) + return in; + if (verbose) + clog << "WARNING: no name found for " << type << endl; + return string("default_anonymous_" ) + type; + } + + void focus_on_module(Dwfl_Module * m) + { + assert(m); + module = m; + module_dwarf = dwfl_module_getdwarf(module, &module_bias); + module_name = default_name(dwfl_module_info(module, NULL, + NULL, NULL, + NULL, NULL, + NULL, NULL), + "module"); + if (verbose) + clog << "focused on module " << module_name << endl; + } + + void focus_on_cu(Dwarf_Die * c) + { + assert(c); + cu = c; + cu_name = default_name(dwarf_diename(c), "cu"); + if (verbose) + clog << "focused on CU " << cu_name + << ", in module " << module_name << endl; + } + + void focus_on_function(Dwarf_Func * f) + { + assert(f); + function = f; + function_name = default_name(dwarf_func_name(function), + "function"); + if (verbose) + clog << "focused on function " << function_name + << ", in CU " << cu_name + << ", module " << module_name << endl; + } + + void focus_on_module_containing_global_address(Dwarf_Addr a) + { + assert(dwfl); + if (verbose) + clog << "focusing on module containing global addr " << a << endl; + focus_on_module(dwfl_addrmodule(dwfl, a)); + } + + void focus_on_cu_containing_module_address(Dwarf_Addr a) + { + assert(dwfl); + assert(module); + Dwarf_Addr bias; + if (verbose) + clog << "focusing on cu containing module addr " << a << endl; + focus_on_cu(dwfl_module_addrdie(module, a, &bias)); + assert(bias == module_bias); + } + + void focus_on_cu_containing_global_address(Dwarf_Addr a) + { + assert(dwfl); + if (verbose) + clog << "focusing on cu containing global addr " << a << endl; + focus_on_module_containing_global_address(a); + assert(a > module_bias); + a = global_address_to_module(a); + focus_on_cu_containing_module_address(a); + } + + Dwarf_Addr module_address_to_global(Dwarf_Addr a) + { + assert(module); + if (verbose) + clog << "module addr " << a + << " + bias " << module_bias + << " -> global addr " << a + module_bias << endl; + return a + module_bias; + } + + Dwarf_Addr global_address_to_module(Dwarf_Addr a) + { + assert(module); + if (verbose) + clog << "global addr " << a + << " - bias " << module_bias + << " -> module addr " << a - module_bias << endl; + return a - module_bias; + } + + + bool module_name_matches(string pattern) + { + assert(module); + bool t = (fnmatch(pattern.c_str(), module_name.c_str(), 0) == 0); + if (verbose) + clog << "pattern '" << pattern << "' " + << (t ? "matches " : "does not match ") + << "module '" << module_name << "'" << endl; + return t; + } + + bool function_name_matches(string pattern) + { + assert(function); + bool t = (fnmatch(pattern.c_str(), function_name.c_str(), 0) == 0); + if (verbose) + clog << "pattern '" << pattern << "' " + << (t ? "matches " : "does not match ") + << "function '" << function_name << "'" << endl; + return t; + } + + bool cu_name_matches(string pattern) + { + assert(cu); + bool t = (fnmatch(pattern.c_str(), cu_name.c_str(), 0) == 0); + if (verbose) + clog << "pattern '" << pattern << "' " + << (t ? "matches " : "does not match ") + << "CU '" << cu_name << "'" << endl; + return t; + } + + void dwflpp_assert(int rc) + { + if (rc != 0) + throw semantic_error(string("dwfl failure: ") + dwfl_errmsg(rc)); + } + + dwflpp() + : + dwfl(NULL), + module(NULL), + module_dwarf(NULL), + module_bias(0), + cu(NULL), + function(NULL) + {} + + void setup(bool kernel) + { + static const Dwfl_Callbacks proc_callbacks = + { + dwfl_linux_proc_find_elf, + dwfl_standard_find_debuginfo, + NULL, + NULL + }; + + static const Dwfl_Callbacks kernel_callbacks = + { + dwfl_linux_kernel_find_elf, + dwfl_standard_find_debuginfo, + dwfl_linux_kernel_module_section_address, + NULL + }; + + if (kernel) + { + dwfl = dwfl_begin(&kernel_callbacks); + if (!dwfl) + throw semantic_error("cannot open dwfl"); + dwfl_report_begin(dwfl); + dwflpp_assert(dwfl_linux_kernel_report_kernel(dwfl)); + dwflpp_assert(dwfl_linux_kernel_report_modules(dwfl)); + } + else + { + dwfl = dwfl_begin(&proc_callbacks); + dwfl_report_begin(dwfl); + if (!dwfl) + throw semantic_error("cannot open dwfl"); + // XXX: Find pids or processes, do userspace stuff. + } + + dwflpp_assert(dwfl_report_end(dwfl, NULL, NULL)); + } + + void iterate_over_modules(int (* callback)(Dwfl_Module *, void **, + const char *, Dwarf_Addr, + Dwarf *, Dwarf_Addr, void *), + void * data) + { + if (verbose) + clog << "iterating over modules" << endl; + ptrdiff_t off = 0; + do + { + off = dwfl_getdwarf(dwfl, callback, data, off); + } + while (off > 0); + if (verbose) + clog << "finished iterating over modules" << endl; + dwflpp_assert(off); + } + + void iterate_over_cus (int (*callback)(Dwarf_Die * die, void * arg), + void * data) + { + if (!module_dwarf) + { + cerr << "WARNING: no dwarf info found for module " << module_name << endl; + return; + } + + if (verbose) + clog << "iterating over CUs in module " << module_name << endl; + + Dwarf *dw = module_dwarf; + Dwarf_Off off = 0; + size_t cuhl; + Dwarf_Off noff; + while (dwarf_nextcu(dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0) + { + Dwarf_Die die_mem; + Dwarf_Die *die; + die = dwarf_offdie(dw, off + cuhl, &die_mem); + if (callback(die, data) != DWARF_CB_OK) + break; + off = noff; + } + } + + void iterate_over_functions(int (* callback)(Dwarf_Func * func, void * arg), + void * data) + { + assert(module); + assert(cu); + if (verbose) + clog << "iterating over functions in CU " << cu_name << endl; + dwarf_getfuncs(cu, callback, data, 0); + } + + bool function_entrypc(Dwarf_Addr * addr) + { + return (dwarf_func_entrypc(function, addr) == 0); + } + + bool function_includes_global_addr(Dwarf_Addr addr) + { + assert(module_dwarf); + assert(cu); + assert(function); + Dwarf_Addr lo, hi; + if (dwarf_func_lowpc(function, &lo) != 0) + { + if (verbose) + clog << "WARNING: cannot find low PC value for function " << function_name << endl; + return false; + } + + if (dwarf_func_highpc(function, &hi) != 0) + { + if (verbose) + clog << "WARNING: cannot find high PC value for function " << function_name << endl; + return false; + } + + bool t = lo <= addr && addr <= hi; + if (verbose) + clog << "function " << function_name << " = [" << lo << "," << hi << "] " + << (t ? "contains " : "does not contain ") + << " global addr " << addr << endl; + return t; + } + + bool function_includes_module_addr(Dwarf_Addr addr) + { + return function_includes_global_addr(module_address_to_global(addr)); + } + + Dwarf_Addr global_addr_of_line_in_cu(int line) + { + Dwarf_Lines * lines; + size_t nlines; + Dwarf_Addr addr; + Dwarf_Line * linep; + + assert(module); + assert(cu); + dwflpp_assert(dwarf_getsrclines(cu, &lines, &nlines)); + linep = dwarf_onesrcline(lines, line); + dwflpp_assert(dwarf_lineaddr(linep, &addr)); + if (verbose) + clog << "line " << line + << " of cu " << cu_name + << " has module address " << addr + << " in " << module_name << endl; + return module_address_to_global(addr); + } + + + ~dwflpp() + { + if (dwfl) + dwfl_end(dwfl); + } +}; + +enum +function_spec_type + { + function_alone, + function_and_file, + function_file_and_line + }; + +struct dwarf_builder; +struct dwarf_derived_probe : public derived_probe { - bool kernel; - map<string, literal *> params; + dwarf_derived_probe (probe* p, probe_point* l, + map<string, literal *> const & params); + + static string TOK_PROCESS; + static string TOK_KERNEL; + static string TOK_MODULE; + static string TOK_FUNCTION; + static string TOK_STATEMENT; + static string TOK_CALLEES; + static string TOK_RETURN; + static string TOK_RELATIVE; + static string TOK_LABEL; + + // Pattern registration helpers. + static void register_relative_variants(match_node & root, + dwarf_builder * dw); + static void register_statement_variants(match_node & root, + dwarf_builder * dw); + static void register_callee_variants(match_node & root, + dwarf_builder * dw); + static void register_function_and_statement_variants(match_node & root, + dwarf_builder * dw); + static void register_patterns(match_node & root); + + // Parameter extractors. + static bool has_null_param(map<string, literal *> const & params, + string const & k); + static bool get_string_param(map<string, literal *> const & params, + string const & k, string & v); + static bool get_number_param(map<string, literal *> const & params, + string const & k, long & v); - dwarf_derived_probe (probe* p, probe_point* l, bool kernel, - map<string, literal *> const & params): - derived_probe (p, l), - kernel (kernel) {} + // The results of all our hard work go in this vector. + vector<Dwarf_Addr> addresses; + // Helper struct to thread through the dwfl callbacks. + struct + dwarf_query + { + dwarf_query(dwflpp & d, + vector<Dwarf_Addr> & a, + token const * tok, + map<string, literal *> const & params); + + bool has_kernel; + bool has_process; + bool has_module; + string process_val; + string module_val; + string function_val; + + bool has_function_str; + bool has_statement_str; + bool has_function_num; + bool has_statement_num; + string statement_str_val; + string function_str_val; + long statement_num_val; + long function_num_val; + + bool has_callees; + long callee_val; + + bool has_return; + + bool has_label; + string label_val; + + bool has_relative; + long relative_val; + + function_spec_type parse_function_spec(string & spec); + function_spec_type spec_type; + string function; + string file; + int line; + + + dwflpp & dw; + vector<Dwarf_Addr> & addrs; + token const * tok; + }; + virtual void emit_registrations (translator_output* o, unsigned i); virtual void emit_deregistrations (translator_output* o, unsigned i); virtual void emit_probe_entries (translator_output* o, unsigned i); @@ -343,20 +766,448 @@ struct dwarf_builder : public derived_probe_builder { - bool begin; - dwarf_builder(bool b) : begin(b) {} + dwarf_builder() {} virtual derived_probe * build(probe * base, probe_point * location, map<string, literal *> const & parameters) { - return new dwarf_derived_probe(base, location, begin, parameters); + return new dwarf_derived_probe(base, location, parameters); } virtual ~dwarf_builder() {} }; +bool +dwarf_derived_probe::has_null_param(map<string, literal *> const & params, + string const & k) +{ + map<string, literal *>::const_iterator i = params.find(k); + if (i != params.end() && i->second == NULL) + return true; + return false; +} + +bool +dwarf_derived_probe::get_string_param(map<string, literal *> const & params, + string const & k, string & v) +{ + map<string, literal *>::const_iterator i = params.find(k); + if (i == params.end()) + return false; + literal_string * ls = dynamic_cast<literal_string *>(i->second); + if (!ls) + return false; + v = ls->value; + return true; +} + +bool +dwarf_derived_probe::get_number_param(map<string, literal *> const & params, + string const & k, long & v) +{ + map<string, literal *>::const_iterator i = params.find(k); + if (i == params.end()) + return false; + if (i->second == NULL) + return false; + literal_number * ln = dynamic_cast<literal_number *>(i->second); + if (!ln) + return false; + v = ln->value; + return true; +} + + +dwarf_derived_probe::dwarf_query::dwarf_query(dwflpp & d, + vector<Dwarf_Addr> & a, + token const * tok, + map<string, literal *> const & params) + : dw(d), addrs(a), tok(tok) +{ + // Reduce the query to more reasonable semantic values (booleans, + // extracted strings, numbers, etc). + + has_kernel = has_null_param(params, TOK_KERNEL); + has_module = get_string_param(params, TOK_MODULE, module_val); + has_process = get_string_param(params, TOK_PROCESS, process_val); + + has_function_str = get_string_param(params, TOK_FUNCTION, function_str_val); + has_function_num = get_number_param(params, TOK_FUNCTION, function_num_val); + + has_statement_str = get_string_param(params, TOK_STATEMENT, statement_str_val); + has_statement_num = get_number_param(params, TOK_STATEMENT, statement_num_val); + + callee_val = 1; + has_callees = (has_null_param(params, TOK_CALLEES) || + get_number_param(params, TOK_CALLEES, callee_val)); + + has_return = has_null_param(params, TOK_RETURN); + + has_label = get_string_param(params, TOK_LABEL, label_val); + has_relative = get_number_param(params, TOK_RELATIVE, relative_val); + + if (has_function_str) + spec_type = parse_function_spec(function_str_val); + else if (has_statement_str) + spec_type = parse_function_spec(statement_str_val); +} + + +template <typename OUT, typename IN> inline OUT +lex_cast(IN const & in) +{ + stringstream ss; + OUT out; + if (!(ss << in && ss >> out)) + throw runtime_error("bad lexical cast"); + return out; +} + +function_spec_type +dwarf_derived_probe::dwarf_query::parse_function_spec(string & spec) +{ + string::const_iterator i = spec.begin(), e = spec.end(); + + function.clear(); + file.clear(); + line = 0; + + while (i != e && *i != '@') + { + if (*i == ':') + goto bad; + function += *i++; + } + + if (i == e) + { + if (verbose) + clog << "parsed '" << spec + << "' -> func '" << function + << "'" << endl; + return function_alone; + } + + if (i++ == e) + goto bad; + + while (i != e && *i != ':') + file += *i++; + + if (i == e) + { + if (verbose) + clog << "parsed '" << spec + << "' -> func '"<< function + << "', file '" << file + << "'" << endl; + return function_and_file; + } + + if (i++ == e) + goto bad; + + try + { + line = lex_cast<int>(string(i, e)); + if (verbose) + clog << "parsed '" << spec + << "' -> func '"<< function + << "', file '" << file + << "', line " << line << endl; + return function_file_and_line; + } + catch (runtime_error & exn) + { + goto bad; + } + + bad: + throw semantic_error("malformed specification '" + spec + "'", tok); +} + + +static void +query_statement(Dwarf_Addr stmt_addr, dwarf_derived_probe::dwarf_query *q) +{ + // XXX: implement + if (q->has_relative) + throw semantic_error("incomplete: do not know how to interpret .relative", q->tok); + q->addrs.push_back(stmt_addr); +} + +static int +query_function(Dwarf_Func * func, void * arg) +{ + + dwarf_derived_probe::dwarf_query *q = + static_cast<dwarf_derived_probe::dwarf_query *>(arg); + + // XXX: implement + if (q->has_callees) + throw semantic_error("incomplete: do not know how to interpret .callees", q->tok); + + if (q->has_return) + throw semantic_error("incomplete: do not know how to interpret .return", q->tok); + + if (q->has_label) + throw semantic_error("incomplete: do not know how to interpret .label", q->tok); + + q->dw.focus_on_function(func); + + Dwarf_Addr addr; + if (!q->dw.function_entrypc(&addr)) + return DWARF_CB_OK; + + if ((q->has_statement_str || q->has_function_str) + && q->dw.function_name_matches(q->function)) + { + // If this function's name matches a function or statement + // pattern, we use its entry pc, but we do not abort iteration + // since there might be other functions matching the pattern. + query_statement(addr, q); + } + else if (q->has_kernel + && q->has_function_num + && q->dw.function_includes_global_addr(q->function_num_val)) + { + // If this function's address range matches a kernel-relative + // function address, we use its entry pc and break out of the + // iteration, since there can only be one such function. + query_statement(addr, q); + return DWARF_CB_ABORT; + } + else if (q->has_module + && q->has_function_num + && q->dw.function_includes_module_addr(q->function_num_val)) + { + // If this function's address range matches a module-relative + // function address, we use its entry pc and break out of the + // iteration, since there can only be one such function. + query_statement(addr, q); + return DWARF_CB_ABORT; + } + + return DWARF_CB_OK; +} + +static int +query_cu (Dwarf_Die * cudie, void * arg) +{ + dwarf_derived_probe::dwarf_query *q = + static_cast<dwarf_derived_probe::dwarf_query *>(arg); + + q->dw.focus_on_cu(cudie); + + // If we have enough information in the pattern to skip a CU + // and the CU does not match that information, return early. + if ((q->has_statement_str || q->has_function_str) + && (q->spec_type == function_file_and_line || + q->spec_type == function_and_file) + && (!q->dw.cu_name_matches(q->file))) + return DWARF_CB_OK; + + if (q->has_statement_str + && (q->spec_type == function_file_and_line) + && q->dw.cu_name_matches(q->file)) + { + // If we have a complete file:line statement + // functor (not function functor) landing on + // this CU, we can look up a specific address + // for the statement, and skip scanning + // the remaining functions within the CU. + query_statement(q->dw.global_addr_of_line_in_cu(q->line), q); + } + else + { + // Otherwise we need to scan all the functions in this CU. + q->dw.iterate_over_functions(&query_function, q); + } + return DWARF_CB_OK; +} + +static int +query_module (Dwfl_Module *mod __attribute__ ((unused)), + void **userdata __attribute__ ((unused)), + const char *name, Dwarf_Addr base, + Dwarf *dw, Dwarf_Addr bias, + void *arg __attribute__ ((unused))) +{ + + dwarf_derived_probe::dwarf_query *q = + static_cast<dwarf_derived_probe::dwarf_query *>(arg); + + q->dw.focus_on_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; + + if (q->has_function_num || q->has_statement_num) + { + // If we have module("foo").function(0xbeef) or + // module("foo").statement(0xbeef), the address is relative + // to the start of the module, so we seek the function + // number plus the module's bias. + Dwarf_Addr addr; + if (q->has_function_num) + addr = q->function_num_val; + else + addr = q->function_num_val; + + q->dw.focus_on_cu_containing_module_address(addr); + q->dw.iterate_over_functions(&query_function, q); + } + else + { + // Otherwise if we have a function("foo") or statement("foo") + // specifier, we have to scan over all the CUs looking for + // the function in question + assert(q->has_function_str || q->has_statement_str); + q->dw.iterate_over_cus(&query_cu, q); + } + + return DWARF_CB_OK; +} + +dwarf_derived_probe::dwarf_derived_probe (probe* p, probe_point* l, + map<string, literal *> const & params) + : derived_probe (p, l) +{ + dwflpp dw; + dwarf_query q(dw, addresses, p->tok, params); + dw.setup(q.has_kernel || q.has_module); + + if (q.has_kernel && q.has_statement_num) + { + // If we have kernel.statement(0xbeef), the address is global + // (relative to the kernel) and we can seek directly to the + // statement in question. + query_statement(q.statement_num_val, &q); + } + else if (q.has_kernel && q.has_function_num) + { + // If we have kernel.function(0xbeef), the address is global + // (relative to the kernel) and we can seek directly to the + // cudie in question. + dw.focus_on_cu_containing_global_address(q.function_num_val); + dw.iterate_over_functions(&query_function, &q); + } + else + { + // Otherwise we have module("foo"), kernel.statement("foo"), or + // kernel.function("foo"); in these cases we need to scan all + // the modules. + assert((q.has_kernel && q.has_function_str) || + (q.has_kernel && q.has_statement_str) || + (q.has_module)); + dw.iterate_over_modules(&query_module, &q); + } +} + +string dwarf_derived_probe::TOK_PROCESS("process"); +string dwarf_derived_probe::TOK_KERNEL("kernel"); +string dwarf_derived_probe::TOK_MODULE("module"); + +string dwarf_derived_probe::TOK_FUNCTION("function"); +string dwarf_derived_probe::TOK_RETURN("return"); +string dwarf_derived_probe::TOK_CALLEES("callees"); + +string dwarf_derived_probe::TOK_STATEMENT("statement"); +string dwarf_derived_probe::TOK_LABEL("label"); +string dwarf_derived_probe::TOK_RELATIVE("relative"); + + +void +dwarf_derived_probe::register_relative_variants(match_node & root, + dwarf_builder * dw) +{ + // Here we match 2 forms: + // + // . + // .relative(NN) + + root.bind(dw); + root.bind_num(TOK_RELATIVE).bind(dw); +} + +void +dwarf_derived_probe::register_statement_variants(match_node & root, + dwarf_builder * dw) +{ + // Here we match 3 forms: + // + // . + // .return + // .label("foo") + + register_relative_variants(root, dw); + register_relative_variants(root.bind(TOK_RETURN), dw); + register_relative_variants(root.bind_str(TOK_LABEL), dw); +} + +void +dwarf_derived_probe::register_callee_variants(match_node & root, + dwarf_builder * dw) +{ + // Here we match 3 forms: + // + // . + // .callees + // .callees(N) + // + // The last form permits N-level callee resolving without any + // recursive .callees.callees.callees... pattern-matching on our part. + + register_statement_variants(root, dw); + register_statement_variants(root.bind(TOK_CALLEES), dw); + register_statement_variants(root.bind_num(TOK_CALLEES), dw); +} + +void +dwarf_derived_probe::register_function_and_statement_variants(match_node & root, + dwarf_builder * dw) +{ + // Here we match 4 forms: + // + // .function("foo") + // .function(0xdeadbeef) + // .statement("foo") + // .statement(0xdeadbeef) + + register_callee_variants(root.bind_str(TOK_FUNCTION), dw); + register_callee_variants(root.bind_num(TOK_FUNCTION), dw); + register_statement_variants(root.bind_str(TOK_STATEMENT), dw); + register_statement_variants(root.bind_num(TOK_STATEMENT), dw); +} + +void +dwarf_derived_probe::register_patterns(match_node & root) +{ + dwarf_builder *dw = new dwarf_builder(); + + // Here we match 3 forms: + // + // .kernel + // .module("foo") + // .process("foo") + + register_function_and_statement_variants(root.bind(TOK_KERNEL), dw); + register_function_and_statement_variants(root.bind_str(TOK_MODULE), dw); + register_function_and_statement_variants(root.bind_str(TOK_PROCESS), dw); +} + void dwarf_derived_probe::emit_registrations (translator_output* o, unsigned i) { + // XXX: Emit code to register prope properly. + for (unsigned j=0; j<addresses.size(); j++) + { + o->newline() << "// probe " + << i << ", addr " + << j << ", at kernel address: 0x" + << hex << addresses[i]; + } } void @@ -372,21 +1223,15 @@ dwarf_derived_probe::emit_probe_entries (translator_output* o, unsigned i) // ------------------------------------------------------------------------ -// standard tapset registry +// Standard tapset registry. // ------------------------------------------------------------------------ void register_standard_tapsets(match_node & root) { - // rudimentary binders for begin and end targets + // Rudimentary binders for begin and end targets root.bind("begin").bind(new be_builder(true)); root.bind("end").bind(new be_builder(false)); - - // various flavours of dwarf lookup (on the kernel) - dwarf_builder *kern = new dwarf_builder(true); - root.bind("kernel").bind_str("function").bind(kern); - root.bind("kernel").bind_str("function").bind_num("line").bind(kern); - root.bind_str("module").bind(kern); - root.bind_str("module").bind_str("function").bind(kern); - + + dwarf_derived_probe::register_patterns(root); } |