diff options
author | Josh Stone <jistone@redhat.com> | 2009-02-18 12:53:08 -0800 |
---|---|---|
committer | Josh Stone <jistone@redhat.com> | 2009-02-18 12:53:08 -0800 |
commit | 23ad66b41ded81502948584816390c634f66c5ee (patch) | |
tree | db900ca0141a16152c3bf27395cd4975cad6a1ab | |
parent | 2aa2ccb83142c3bf98ac8ee1558a0ee72dff3a1f (diff) | |
parent | 482fe2af17347b472232c5d7c4b26e53606e395e (diff) | |
download | systemtap-steved-23ad66b41ded81502948584816390c634f66c5ee.tar.gz systemtap-steved-23ad66b41ded81502948584816390c634f66c5ee.tar.xz systemtap-steved-23ad66b41ded81502948584816390c634f66c5ee.zip |
Enable typecasting with @cast
println(@cast(myptr, "task_struct")->pid)
println(@cast(myptr, "task_struct", "kernel")->pid)
Merge branch 'typecast', bump ChangeLog entries to push date
-rw-r--r-- | ChangeLog | 53 | ||||
-rw-r--r-- | elaborate.cxx | 39 | ||||
-rw-r--r-- | elaborate.h | 3 | ||||
-rw-r--r-- | loc2c.c | 37 | ||||
-rw-r--r-- | loc2c.h | 15 | ||||
-rw-r--r-- | parse.cxx | 51 | ||||
-rw-r--r-- | session.h | 7 | ||||
-rw-r--r-- | staptree.cxx | 66 | ||||
-rw-r--r-- | staptree.h | 17 | ||||
-rw-r--r-- | tapsets.cxx | 376 | ||||
-rw-r--r-- | translate.cxx | 10 |
11 files changed, 631 insertions, 43 deletions
@@ -1,3 +1,56 @@ +2009-02-18 Josh Stone <jistone@redhat.com> + + * loc2c.c (c_translate_argument): Create a dummy location to start + the address computation from a function parameter. + * translate.cxx (base_query, dwarf_query): Move some members from + base_query to dwarf_query, so the former can be more generic. Also + add a constructor using a module string instead of probe parameters. + (dwflpp::query_modules, dwflpp::iterate_over_modules): Use a generic + base_query instead of a dwarf_query. + (dwarf_cast_query): New query to scan the modules and CUs for a + matching type definition, and then produce a code fragment to deref + each component. + (dwarf_cast_expanding_visitor): Tries to replace @casts with a function + call to the result of a dwarf_cast_query. + (dwflpp::declaration_resolve): Search by name instead of by die. + (dwflpp::translate_components): Use the incoming vardie as the first + type die, so we don't assume that attr_mem has a DW_AT_type already. + (dwflpp::literal_stmt_for_pointer): Construct a C fragment that starts + with a pointer argument (THIS->pointer) and dereferences each member + component from there. + (*_derived_probe::register_patterns): Take a session parameter instead + of a match_node, so we can manipulate session-wide data. + (dwarf_derived_probe::register_patterns): Add a session code filter to + expand @casts with a dwarf_cast_expanding_visitor. + +2009-02-18 Josh Stone <jistone@redhat.com> + + * session.h (systemtap_session): Add a vector of update_visitors + that will act as filters for all probes and functions. + * elaborate.cxx (semantic_pass_symbols): Run probes and functions + through each registered code filter. + +2009-02-18 Josh Stone <jistone@redhat.com> + + * tapsets.cxx (dwarf_var_expanding_visitor::visit_cast_op): While + expanding dwarf probes, provide the current module as a default to + @casts without a module name. + +2009-02-18 Josh Stone <jistone@redhat.com> + + * staptree.h (struct cast_op, visitor::visit_cast_op): New. + * staptree.cxx (cast_op::print/visit, various visitor::visit_cast_op's): + Incorporate cast_op into the basic tree operations. + * parse.cxx (parser::parse_symbol): Parse @cast operator with an + expression operand, type string, and optional module string. + * translate.cxx (c_unparser::visit_cast_op): Error out if a @cast + survives to translation. + * elaborate.cxx (typeresolution_info::visit_cast_op): Error out if a + @cast survives to type resolution. + (symbol_fetcher::visit_cast_op): treat @casts as a symbol target + (void_statement_reducer::visit_cast_op): unused @casts can be discarded, + but the operand should still be evaluated. + 2009-02-17 Frank Ch. Eigler <fche@elastic.org> * AUTHORS: Regenerated with ... diff --git a/elaborate.cxx b/elaborate.cxx index ba50defb..02229fbe 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -1,5 +1,5 @@ // elaboration functions -// Copyright (C) 2005-2008 Red Hat Inc. +// Copyright (C) 2005-2009 Red Hat Inc. // Copyright (C) 2008 Intel Corporation // // This file is part of systemtap, and is free software. You can @@ -701,6 +701,11 @@ struct symbol_fetcher e->base->visit_indexable (this); } + void visit_cast_op (cast_op* e) + { + sym = e; + } + void throwone (const token* t) { throw semantic_error ("Expecting symbol or array index expression", t); @@ -1087,6 +1092,9 @@ semantic_pass_symbols (systemtap_session& s) try { + for (unsigned j=0; j<s.code_filters.size(); j++) + fd->body = s.code_filters[j]->require (fd->body); + sym.current_function = fd; sym.current_probe = 0; fd->body->visit (& sym); @@ -1119,6 +1127,9 @@ semantic_pass_symbols (systemtap_session& s) try { + for (unsigned k=0; k<s.code_filters.size(); k++) + dp->body = s.code_filters[k]->require (dp->body); + sym.current_function = 0; sym.current_probe = dp; dp->body->visit (& sym); @@ -2505,6 +2516,7 @@ struct void_statement_reducer: public update_visitor void visit_concatenation (concatenation* e); void visit_functioncall (functioncall* e); void visit_print_format (print_format* e); + void visit_cast_op (cast_op* e); // these are a bit hairy to grok due to the intricacies of indexables and // stats, so I'm chickening out and skipping them... @@ -2772,6 +2784,19 @@ void_statement_reducer::visit_print_format (print_format* e) provide (e); } +void +void_statement_reducer::visit_cast_op (cast_op* e) +{ + // When the result of a cast operation isn't needed, it's just as good to + // evaluate the operand directly + + if (session.verbose>2) + clog << "Eliding unused typecast " << *e->tok << endl; + + relaxed_p = false; + e->operand->visit(this); +} + void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p) { @@ -3399,6 +3424,18 @@ typeresolution_info::visit_target_symbol (target_symbol* e) void +typeresolution_info::visit_cast_op (cast_op* e) +{ + // Like target_symbol, a cast_op shouldn't survive this far + // unless it was not resolved and its value is really needed. + if (e->saved_conversion_error) + throw (* (e->saved_conversion_error)); + else + throw semantic_error("unresolved cast expression", e->tok); +} + + +void typeresolution_info::visit_arrayindex (arrayindex* e) { diff --git a/elaborate.h b/elaborate.h index c8697595..715a37df 100644 --- a/elaborate.h +++ b/elaborate.h @@ -1,5 +1,5 @@ // -*- C++ -*- -// Copyright (C) 2005-2008 Red Hat Inc. +// Copyright (C) 2005-2009 Red Hat Inc. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General @@ -95,6 +95,7 @@ struct typeresolution_info: public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; @@ -1021,6 +1021,43 @@ c_translate_location (struct obstack *pool, return NULL; } +/* Translate a C fragment for a direct argument VALUE. On errors, call FAIL, + which should not return. Any later errors will use FAIL and FAIL_ARG from + this translate call. On success, return the fragment created. */ +struct location * +c_translate_argument (struct obstack *pool, + void (*fail) (void *arg, const char *fmt, ...) + __attribute__ ((noreturn, format (printf, 2, 3))), + void *fail_arg, + void (*emit_address) (void *fail_arg, + struct obstack *, Dwarf_Addr), + int indent, const char *value) +{ + indent += 2; + + obstack_printf(pool, "%*saddr = %s;\n", indent * 2, "", value); + obstack_1grow (pool, '\0'); + char *program = obstack_finish (pool); + + struct location *loc = obstack_alloc (pool, sizeof *loc); + loc->next = NULL; + loc->fail = fail; + loc->fail_arg = fail_arg; + loc->emit_address = emit_address; + loc->ops = NULL; + loc->nops = 0; + loc->byte_size = 0; + loc->type = loc_address; + loc->frame_base = NULL; + loc->address.declare = NULL; + loc->address.program = program; + loc->address.stack_depth = 0; + loc->address.used_deref = false; + + return loc; +} + + /* Emit "uintNN_t TARGET = ...;". */ static bool emit_base_fetch (struct obstack *pool, Dwarf_Word byte_size, @@ -85,6 +85,21 @@ c_translate_pointer_store (struct obstack *pool, int indent, Dwarf_Die *typedie, struct location **input, const char *rvalue); +/* Translate a C fragment for a direct argument VALUE. On errors, call FAIL, + which should not return. Any later errors will use FAIL and FAIL_ARG from + this translate call. On success, return the fragment created. */ +struct location *c_translate_argument (struct obstack *, + void (*fail) (void *arg, + const char *fmt, ...) + __attribute__ ((noreturn, + format (printf, 2, 3))), + void *fail_arg, + void (*emit_address) (void *fail_arg, + struct obstack *, + Dwarf_Addr), + int indent, const char *value); + + /* Emit the C fragment built up at LOC (i.e., the return value from the first c_translate_location call made). INDENT should match that @@ -1,5 +1,5 @@ // recursive descent parser for systemtap scripts -// Copyright (C) 2005-2007 Red Hat Inc. +// Copyright (C) 2005-2009 Red Hat Inc. // Copyright (C) 2006 Intel Corporation. // Copyright (C) 2007 Bull S.A.S // @@ -2331,7 +2331,54 @@ parser::parse_symbol () bool pf_stream, pf_format, pf_delim, pf_newline, pf_char; - if (name.size() > 0 && name[0] == '@') + if (name == "@cast") + { + // type-punning time + cast_op *cop = new cast_op; + cop->tok = t; + cop->base_name = name; + expect_op("("); + cop->operand = parse_expression (); + expect_op(","); + expect_unknown(tok_string, cop->type); + if (peek_op (",")) + { + next(); + expect_unknown(tok_string, cop->module); + } + expect_op(")"); + while (true) + { + string c; + if (peek_op ("->")) + { + next(); + expect_ident_or_keyword (c); + cop->components.push_back + (make_pair (target_symbol::comp_struct_member, c)); + } + else if (peek_op ("[")) + { + next(); + expect_unknown (tok_number, c); + expect_op ("]"); + cop->components.push_back + (make_pair (target_symbol::comp_literal_array_index, c)); + } + else + break; + } + // if there aren't any dereferences, then the cast is pointless + if (cop->components.empty()) + { + expression *op = cop->operand; + delete cop; + return op; + } + return cop; + } + + else if (name.size() > 0 && name[0] == '@') { stat_op *sop = new stat_op; if (name == "@avg") @@ -1,5 +1,5 @@ // -*- C++ -*- -// Copyright (C) 2005-2008 Red Hat Inc. +// Copyright (C) 2005-2009 Red Hat Inc. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General @@ -45,6 +45,7 @@ struct translator_output; struct unparser; struct semantic_error; struct module_cache; +struct update_visitor; // XXX: a generalized form of this descriptor could be associated with @@ -133,6 +134,10 @@ struct systemtap_session stapfile* user_file; std::vector<stapfile*> library_files; + // filters to run over all code before symbol resolution + // e.g. @cast expansion + std::vector<update_visitor*> code_filters; + // resolved globals/functions/probes for the run as a whole std::vector<stapfile*> files; std::vector<vardecl*> globals; diff --git a/staptree.cxx b/staptree.cxx index 9ffbaf09..8d251731 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -1,5 +1,5 @@ // parse tree functions -// Copyright (C) 2005-2008 Red Hat Inc. +// Copyright (C) 2005-2009 Red Hat Inc. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General @@ -277,6 +277,28 @@ void target_symbol::print (std::ostream& o) const } +void cast_op::print (std::ostream& o) const +{ + o << base_name << '(' << *operand; + o << ", " << lex_cast_qstring (type); + if (module.length() > 0) + o << ", " << lex_cast_qstring (module); + o << ')'; + for (unsigned i = 0; i < components.size(); ++i) + { + switch (components[i].first) + { + case comp_literal_array_index: + o << '[' << components[i].second << ']'; + break; + case comp_struct_member: + o << "->" << components[i].second; + break; + } + } +} + + void vardecl::print (ostream& o) const { o << name; @@ -1220,6 +1242,12 @@ target_symbol::visit (visitor* u) } void +cast_op::visit (visitor* u) +{ + u->visit_cast_op(this); +} + +void arrayindex::visit (visitor* u) { u->visit_arrayindex (this); @@ -1586,6 +1614,12 @@ traversing_visitor::visit_target_symbol (target_symbol*) } void +traversing_visitor::visit_cast_op (cast_op* e) +{ + e->operand->visit (this); +} + +void traversing_visitor::visit_arrayindex (arrayindex* e) { for (unsigned i=0; i<e->indexes.size(); i++) @@ -1680,6 +1714,17 @@ varuse_collecting_visitor::visit_target_symbol (target_symbol *e) } void +varuse_collecting_visitor::visit_cast_op (cast_op *e) +{ + // As with target_symbols, unresolved cast assignments need to preserved + // for later error handling. + if (is_active_lvalue (e)) + embedded_seen = true; + + functioncall_traversing_visitor::visit_cast_op (e); +} + +void varuse_collecting_visitor::visit_print_format (print_format* e) { // NB: Instead of being top-level statements, "print" and "printf" @@ -2064,6 +2109,12 @@ throwing_visitor::visit_target_symbol (target_symbol* e) } void +throwing_visitor::visit_cast_op (cast_op* e) +{ + throwone (e->tok); +} + +void throwing_visitor::visit_arrayindex (arrayindex* e) { throwone (e->tok); @@ -2297,6 +2348,13 @@ update_visitor::visit_target_symbol (target_symbol* e) } void +update_visitor::visit_cast_op (cast_op* e) +{ + e->operand = require (e->operand); + provide (e); +} + +void update_visitor::visit_arrayindex (arrayindex* e) { e->base = require (e->base); @@ -2528,6 +2586,12 @@ deep_copy_visitor::visit_target_symbol (target_symbol* e) } void +deep_copy_visitor::visit_cast_op (cast_op* e) +{ + update_visitor::visit_cast_op(new cast_op(*e)); +} + +void deep_copy_visitor::visit_arrayindex (arrayindex* e) { update_visitor::visit_arrayindex(new arrayindex(*e)); @@ -1,5 +1,5 @@ // -*- C++ -*- -// Copyright (C) 2005-2008 Red Hat Inc. +// Copyright (C) 2005-2009 Red Hat Inc. // Copyright (C) 2006 Intel Corporation. // // This file is part of systemtap, and is free software. You can @@ -238,6 +238,15 @@ struct target_symbol: public symbol }; +struct cast_op: public target_symbol +{ + expression *operand; + std::string type, module; + void print (std::ostream& o) const; + void visit (visitor* u); +}; + + struct arrayindex: public expression { std::vector<expression*> indexes; @@ -680,6 +689,7 @@ struct visitor virtual void visit_print_format (print_format* e) = 0; virtual void visit_stat_op (stat_op* e) = 0; virtual void visit_hist_op (hist_op* e) = 0; + virtual void visit_cast_op (cast_op* e) = 0; }; @@ -720,6 +730,7 @@ struct traversing_visitor: public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; @@ -759,6 +770,7 @@ struct varuse_collecting_visitor: public functioncall_traversing_visitor void visit_pre_crement (pre_crement *e); void visit_post_crement (post_crement *e); void visit_foreach_loop (foreach_loop *s); + void visit_cast_op (cast_op* e); bool side_effect_free (); bool side_effect_free_wrt (const std::set<vardecl*>& vars); @@ -808,6 +820,7 @@ struct throwing_visitor: public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; // A visitor similar to a traversing_visitor, but with the ability to rewrite @@ -868,6 +881,7 @@ struct update_visitor: public visitor virtual void visit_print_format (print_format* e); virtual void visit_stat_op (stat_op* e); virtual void visit_hist_op (hist_op* e); + virtual void visit_cast_op (cast_op* e); private: std::stack<void *> targets; @@ -922,6 +936,7 @@ struct deep_copy_visitor: public update_visitor virtual void visit_print_format (print_format* e); virtual void visit_stat_op (stat_op* e); virtual void visit_hist_op (hist_op* e); + virtual void visit_cast_op (cast_op* e); }; #endif // STAPTREE_H diff --git a/tapsets.cxx b/tapsets.cxx index 45a63e6f..6ce574f0 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -539,7 +539,8 @@ inline_instance_info }; -struct dwarf_query; // forward decls +struct base_query; // forward decls +struct dwarf_query; struct dwflpp; struct symbol_table; @@ -1011,7 +1012,7 @@ struct dwflpp void iterate_over_modules(int (* callback)(Dwfl_Module *, void **, const char *, Dwarf_Addr, void *), - dwarf_query *data) + base_query *data) { ptrdiff_t off = 0; do @@ -1029,7 +1030,7 @@ struct dwflpp // Defined after dwarf_query - void query_modules(dwarf_query *q); + void query_modules(base_query *q); // ----------------------------------------------------------------- @@ -1146,10 +1147,8 @@ struct dwflpp return DWARF_CB_OK; } - Dwarf_Die *declaration_resolve(Dwarf_Die *die) + Dwarf_Die *declaration_resolve(const char *name) { - const char *name = dwarf_diename(die); - if (!name) return NULL; @@ -1949,12 +1948,15 @@ struct dwflpp Dwarf_Die *die_mem, Dwarf_Attribute *attr_mem) { - Dwarf_Die *die = vardie; + Dwarf_Die *die = die_mem; Dwarf_Die struct_die; Dwarf_Attribute temp_attr; unsigned i = 0; + if (vardie) + *die_mem = *vardie; + static unsigned int func_call_level ; static unsigned int dwarf_error_flag ; // indicates current error is dwarf error static unsigned int dwarf_error_count ; // keeps track of no of dwarf errors @@ -1971,7 +1973,6 @@ struct dwflpp obstack_printf (pool, "c->last_stmt = %s;", lex_cast_qstring(piece).c_str()); #endif - die = dwarf_formref_die (attr_mem, die_mem); const int typetag = dwarf_tag (die); switch (typetag) { @@ -2008,7 +2009,7 @@ struct dwflpp struct_die = *die; if (dwarf_hasattr(die, DW_AT_declaration)) { - Dwarf_Die *tmpdie = dwflpp::declaration_resolve(die); + Dwarf_Die *tmpdie = dwflpp::declaration_resolve(dwarf_diename(die)); if (tmpdie == NULL) throw semantic_error ("unresolved struct " + string (dwarf_diename_integrate (die) ?: "<anonymous>")); @@ -2122,6 +2123,7 @@ struct dwflpp /* 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))); + die = dwarf_formref_die (attr_mem, die_mem); } return die; } @@ -2365,8 +2367,9 @@ struct dwflpp /* Translate the ->bar->baz[NN] parts. */ Dwarf_Die die_mem, *die = NULL; + die = dwarf_formref_die (&attr_mem, &die_mem); die = translate_components (&pool, &tail, pc, components, - &vardie, &die_mem, &attr_mem); + die, &die_mem, &attr_mem); if(!die) { die = dwarf_formref_die (&attr_mem, &vardie); @@ -2483,6 +2486,60 @@ struct dwflpp } + string + literal_stmt_for_pointer (Dwarf_Die *type_die, + vector<pair<target_symbol::component_type, + std::string> > const & components, + 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, components, + type_die, &die_mem, &attr_mem); + if(!die) + { + die = dwarf_formref_die (&attr_mem, &die_mem); + stringstream alternatives; + print_members(die ?: type_die, alternatives); + throw semantic_error("unable to find member for struct " + + string(dwarf_diename(die ?: type_die) ?: "<unknown>") + + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")"))); + } + + + /* 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, + prelude, postlude, ty); + + /* Write the translation to a string. */ + return express_as_string(prelude, postlude, head); + } + + ~dwflpp() { if (dwfl) @@ -2539,7 +2596,7 @@ struct dwarf_derived_probe: public derived_probe dwarf_builder * dw); static void register_function_and_statement_variants(match_node * root, dwarf_builder * dw); - static void register_patterns(match_node * root); + static void register_patterns(systemtap_session& s); }; @@ -2594,19 +2651,12 @@ public: // Helper struct to thread through the dwfl callbacks. struct base_query { - base_query(systemtap_session & sess, - probe * base_probe, - probe_point * base_loc, - dwflpp & dw, - literal_map_t const & params, - vector<derived_probe *> & results); + base_query(dwflpp & dw, literal_map_t const & params); + base_query(dwflpp & dw, const string & module_val); virtual ~base_query() {} systemtap_session & sess; - probe * base_probe; - probe_point * base_loc; dwflpp & dw; - vector<derived_probe *> & results; // Parameter extractors. static bool has_null_param(literal_map_t const & params, @@ -2628,14 +2678,8 @@ struct base_query }; -base_query::base_query(systemtap_session & sess, - probe * base_probe, - probe_point * base_loc, - dwflpp & dw, - literal_map_t const & params, - vector<derived_probe *> & results) - : sess(sess), base_probe(base_probe), base_loc(base_loc), dw(dw), - results(results) +base_query::base_query(dwflpp & dw, literal_map_t const & params): + sess(dw.sess), dw(dw) { has_kernel = has_null_param (params, TOK_KERNEL); if (has_kernel) @@ -2654,6 +2698,24 @@ base_query::base_query(systemtap_session & sess, assert (has_kernel || has_process || has_module); } +base_query::base_query(dwflpp & dw, const string & module_val) + : sess(dw.sess), dw(dw), module_val(module_val) +{ + // NB: This uses '/' to distinguish between kernel modules and userspace, + // which means that userspace modules won't get any PATH searching. + if (module_val.find('/') == string::npos) + { + has_kernel = (module_val == TOK_KERNEL); + has_module = !has_kernel; + has_process = false; + } + else + { + has_kernel = has_module = false; + has_process = true; + } +} + bool base_query::has_null_param(literal_map_t const & params, string const & k) @@ -2700,6 +2762,10 @@ struct dwarf_query : public base_query literal_map_t const & params, vector<derived_probe *> & results); + vector<derived_probe *> & results; + probe * base_probe; + probe_point * base_loc; + virtual void handle_query_module(); void query_module_dwarf(); void query_module_symtab(); @@ -2983,7 +3049,8 @@ dwarf_query::dwarf_query(systemtap_session & sess, dwflpp & dw, literal_map_t const & params, vector<derived_probe *> & results) - : base_query(sess, base_probe, base_loc, dw, params, results) + : base_query(dw, params), results(results), + base_probe(base_probe), base_loc(base_loc) { // Reduce the query to more reasonable semantic values (booleans, // extracted strings, numbers, etc). @@ -4225,7 +4292,7 @@ query_module (Dwfl_Module *mod, } void -dwflpp::query_modules(dwarf_query *q) +dwflpp::query_modules(base_query *q) { iterate_over_modules(&query_module, q); } @@ -4253,6 +4320,7 @@ struct dwarf_var_expanding_visitor: public var_expanding_visitor dwarf_var_expanding_visitor(dwarf_query & q, Dwarf_Die *sd, Dwarf_Addr a): q(q), scope_die(sd), addr(a), add_block(NULL), add_probe(NULL), visited(false) {} void visit_target_symbol (target_symbol* e); + void visit_cast_op (cast_op* e); }; @@ -4812,6 +4880,239 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e) void +dwarf_var_expanding_visitor::visit_cast_op (cast_op *e) +{ + // Fill in our current module context if needed + if (e->module.empty()) + e->module = q.dw.module_name; + + var_expanding_visitor::visit_cast_op(e); +} + + +struct dwarf_cast_query : public base_query +{ + const cast_op& e; + const bool lvalue; + exp_type& pe_type; + + bool resolved; + string code; + + dwarf_cast_query(dwflpp& dw, const cast_op& e, bool lvalue, exp_type& pe_type): + base_query(dw, e.module), e(e), lvalue(lvalue), pe_type(pe_type), resolved(false) {} + const string& get_code(); + + void handle_query_module(); + int handle_query_cu(Dwarf_Die * cudie); + + static int cast_query_cu (Dwarf_Die * cudie, void * arg); +}; + + +const string& +dwarf_cast_query::get_code() +{ + if (!resolved) + dw.query_modules(this); + + if (!resolved) + throw semantic_error("type definition not found"); + + return code; +} + + +void +dwarf_cast_query::handle_query_module() +{ + if (resolved) + return; + + // look for the type in each CU + dw.iterate_over_cus(cast_query_cu, this); +} + + +int +dwarf_cast_query::handle_query_cu(Dwarf_Die * cudie) +{ + if (resolved) + return DWARF_CB_ABORT; + + dw.focus_on_cu (cudie); + Dwarf_Die* type_die = dw.declaration_resolve(e.type.c_str()); + if (type_die) + { + try + { + code = dw.literal_stmt_for_pointer (type_die, e.components, + lvalue, pe_type); + } + catch (const semantic_error& e) + { + // XXX might be better to save the error + // and try again in another CU + sess.print_error (e); + return DWARF_CB_ABORT; + } + + resolved = true; + return DWARF_CB_ABORT; + } + return DWARF_CB_OK; +} + + +int +dwarf_cast_query::cast_query_cu (Dwarf_Die * cudie, void * arg) +{ + dwarf_cast_query * q = static_cast<dwarf_cast_query *>(arg); + if (pending_interrupts) return DWARF_CB_ABORT; + return q->handle_query_cu(cudie); +} + + +struct dwarf_cast_expanding_visitor: public var_expanding_visitor +{ + systemtap_session& s; + dwarf_builder& db; + + dwarf_cast_expanding_visitor(systemtap_session& s, dwarf_builder& db): + s(s), db(db) {} + void visit_cast_op (cast_op* e); +}; + + +void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) +{ + bool lvalue = is_active_lvalue(e); + if (lvalue && !s.guru_mode) + throw semantic_error("write to typecast value not permitted", e->tok); + + if (e->module.empty()) + e->module = "kernel"; // "*" may also be reasonable to search all kernel modules + + if (! s.module_cache) + s.module_cache = new module_cache (); + + string code; + exp_type type = pe_long; + try + { + // NB: This uses '/' to distinguish between kernel modules and userspace, + // which means that userspace modules won't get any PATH searching. + dwflpp* dw; + if (e->module.find('/') == string::npos) + { + // kernel or kernel module target + if (! db.kern_dw) + { + db.kern_dw = new dwflpp(s); + db.kern_dw->setup_kernel(true); + } + dw = db.kern_dw; + } + else + { + e->module = find_executable (e->module); // canonicalize it + + // user-space target; we use one dwflpp instance per module name + // (= program or shared library) + if (db.user_dw.find(e->module) == db.user_dw.end()) + { + dw = new dwflpp(s); + dw->setup_user(e->module); + db.user_dw[e->module] = dw; + } + else + dw = db.user_dw[e->module]; + } + + dwarf_cast_query q (*dw, *e, lvalue, type); + code = q.get_code(); + } + catch (const semantic_error& er) + { + // We suppress this error message, and pass the unresolved + // cast_op to the next pass. We hope that this value ends + // up not being referenced after all, so it can be optimized out + // quietly. + semantic_error* saveme = new semantic_error (er); // copy it + saveme->tok1 = e->tok; // XXX: token not passed to dw code generation routines + // NB: we can have multiple errors, since a @cast + // may be expanded in several different contexts: + // function ("*") { @cast(...) } + saveme->chain = e->saved_conversion_error; + e->saved_conversion_error = saveme; + provide (e); + return; + } + + string fname = (string(lvalue ? "_dwarf_tvar_set" : "_dwarf_tvar_get") + + "_" + e->base_name.substr(1) + + "_" + lex_cast<string>(tick++)); + + // Synthesize a function. + functiondecl *fdecl = new functiondecl; + fdecl->tok = e->tok; + fdecl->type = type; + fdecl->name = fname; + + embeddedcode *ec = new embeddedcode; + ec->tok = e->tok; + ec->code = code; + fdecl->body = ec; + + // Give the fdecl an argument for the pointer we're trying to cast + vardecl *v1 = new vardecl; + v1->type = pe_long; + v1->name = "pointer"; + v1->tok = e->tok; + fdecl->formal_args.push_back(v1); + + if (lvalue) + { + // Modify the fdecl so it carries a second pe_long formal + // argument called "value". + + // FIXME: For the time being we only support setting target + // variables which have base types; these are 'pe_long' in + // stap's type vocabulary. Strings and pointers might be + // reasonable, some day, but not today. + + vardecl *v2 = new vardecl; + v2->type = pe_long; + v2->name = "value"; + v2->tok = e->tok; + fdecl->formal_args.push_back(v2); + } + else + ec->code += "/* pure */"; + + s.functions[fdecl->name] = fdecl; + + // Synthesize a functioncall. + functioncall* n = new functioncall; + n->tok = e->tok; + n->function = fname; + n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session + n->args.push_back(e->operand); + + if (lvalue) + { + // Provide the functioncall to our parent, so that it can be + // used to substitute for the assignment node immediately above + // us. + assert(!target_symbol_setter_functioncalls.empty()); + *(target_symbol_setter_functioncalls.top()) = n; + } + + provide (n); +} + + +void dwarf_derived_probe::printsig (ostream& o) const { // Instead of just printing the plain locations, we add a PC value @@ -4998,10 +5299,14 @@ dwarf_derived_probe::register_function_and_statement_variants(match_node * root, } void -dwarf_derived_probe::register_patterns(match_node * root) +dwarf_derived_probe::register_patterns(systemtap_session& s) { + match_node* root = s.pattern_root; dwarf_builder *dw = new dwarf_builder(); + update_visitor *filter = new dwarf_cast_expanding_visitor(s, *dw); + s.code_filters.push_back(filter); + register_function_and_statement_variants(root->bind(TOK_KERNEL), dw); register_function_and_statement_variants(root->bind_str(TOK_MODULE), dw); root->bind(TOK_KERNEL)->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)->bind(dw); @@ -9077,7 +9382,7 @@ struct timer_builder: public derived_probe_builder literal_map_t const & parameters, vector<derived_probe *> & finished_results); - static void register_patterns(match_node *root); + static void register_patterns(systemtap_session& s); }; void @@ -9148,8 +9453,9 @@ timer_builder::build(systemtap_session & sess, } void -timer_builder::register_patterns(match_node *root) +timer_builder::register_patterns(systemtap_session& s) { + match_node* root = s.pattern_root; derived_probe_builder *builder = new timer_builder(); root = root->bind(TOK_TIMER); @@ -9617,13 +9923,13 @@ register_standard_tapsets(systemtap_session & s) s.pattern_root->bind(TOK_NEVER)->bind(new never_builder()); - timer_builder::register_patterns(s.pattern_root); + timer_builder::register_patterns(s); s.pattern_root->bind(TOK_TIMER)->bind("profile")->bind(new profile_builder()); s.pattern_root->bind("perfmon")->bind_str("counter") ->bind(new perfmon_builder()); // dwarf-based kprobe/uprobe parts - dwarf_derived_probe::register_patterns(s.pattern_root); + dwarf_derived_probe::register_patterns(s); // XXX: user-space starter set s.pattern_root->bind_num(TOK_PROCESS) diff --git a/translate.cxx b/translate.cxx index 9b7bf6ed..31f2043f 100644 --- a/translate.cxx +++ b/translate.cxx @@ -1,5 +1,5 @@ // translation pass -// Copyright (C) 2005-2008 Red Hat Inc. +// Copyright (C) 2005-2009 Red Hat Inc. // Copyright (C) 2005-2008 Intel Corporation. // // This file is part of systemtap, and is free software. You can @@ -150,6 +150,7 @@ struct c_unparser: public unparser, public visitor void visit_print_format (print_format* e); void visit_stat_op (stat_op* e); void visit_hist_op (hist_op* e); + void visit_cast_op (cast_op* e); }; // A shadow visitor, meant to generate temporary variable declarations @@ -3488,6 +3489,13 @@ c_unparser::visit_target_symbol (target_symbol* e) void +c_unparser::visit_cast_op (cast_op* e) +{ + throw semantic_error("cannot translate general cast expression", e->tok); +} + + +void c_tmpcounter::load_map_indices(arrayindex *e) { symbol *array; |