From 03c75a4a21ef3dba8abbc7e596d2a102427a3d96 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 15 Jul 2009 18:21:56 -0700 Subject: PR5930: Address-op for $target and @cast members This allows the '&' operator to get the address of @cast and $target variable expressions. * staptree.h (target_symbol): add addressof field * staptree.cxx (target_symbol::print): print '&' for addressof (cast_op::print): ditto * parse.cxx (parser::parse_value): allow '&' prefix on $target/@cast * dwflpp.cxx (dwflpp::translate_final_fetch_or_store): allow taking the computed address without actually doing a final fetch. * tapset* (*::visit_target_symbol): throw errors for $vars w/o addresses * testsuite/systemtap.base/cast.stp: add &@cast test * testsuite/semok/target_addr.stp: test '&' on different member types * testsuite/semko/target_addr?.stp: test failure on bitfields/registers --- dwflpp.cxx | 15 +++++++++++++++ parse.cxx | 12 ++++++++++++ staptree.cxx | 4 ++++ staptree.h | 3 ++- tapset-mark.cxx | 3 +++ tapset-perfmon.cxx | 3 +++ tapset-procfs.cxx | 3 +++ tapset-utrace.cxx | 3 +++ tapsets.cxx | 15 +++++++++++++++ testsuite/semko/target_addr1.stp | 6 ++++++ testsuite/semko/target_addr2.stp | 6 ++++++ testsuite/semko/target_addr3.stp | 6 ++++++ testsuite/semok/target_addr.stp | 11 +++++++++++ testsuite/systemtap.base/cast.exp | 3 ++- testsuite/systemtap.base/cast.stp | 9 +++++++++ 15 files changed, 100 insertions(+), 2 deletions(-) create mode 100755 testsuite/semko/target_addr1.stp create mode 100755 testsuite/semko/target_addr2.stp create mode 100755 testsuite/semko/target_addr3.stp create mode 100755 testsuite/semok/target_addr.stp diff --git a/dwflpp.cxx b/dwflpp.cxx index dc7af5d8..79561c73 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -1830,6 +1830,21 @@ dwflpp::translate_final_fetch_or_store (struct obstack *pool, typedie = resolve_unqualified_inner_typedie (&typedie_mem, attr_mem, e); typetag = dwarf_tag (typedie); + /* If we're looking for an address, then we can just provide what + we computed to this point, without using a fetch/store. */ + if (e->addressof) + { + if (lvalue) + throw semantic_error ("cannot write to member address", e->tok); + + if (dwarf_hasattr_integrate (die, DW_AT_bit_offset)) + throw semantic_error ("cannot take address of bit-field", e->tok); + + c_translate_addressof (pool, 1, 0, 0, die, tail, "THIS->__retvalue"); + ty = pe_long; + return; + } + /* Then switch behavior depending on the type of fetch/store we want, and the type and pointer-ness of the final location. */ diff --git a/parse.cxx b/parse.cxx index f3b9eb09..35c78abe 100644 --- a/parse.cxx +++ b/parse.cxx @@ -2239,6 +2239,18 @@ parser::parse_value () throw parse_error ("expected ')'"); return e; } + else if (t->type == tok_operator && t->content == "&") + { + next (); + t = peek (); + if (t->type != tok_identifier || + (t->content != "@cast" && t->content[0] != '$')) + throw parse_error ("expected @cast or $var"); + + target_symbol *ts = static_cast(parse_symbol()); + ts->addressof = true; + return ts; + } else if (t->type == tok_identifier) return parse_symbol (); else diff --git a/staptree.cxx b/staptree.cxx index 8d251731..9e2ca8da 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -261,6 +261,8 @@ void symbol::print (ostream& o) const void target_symbol::print (std::ostream& o) const { + if (addressof) + o << "&"; o << base_name; for (unsigned i = 0; i < components.size(); ++i) { @@ -279,6 +281,8 @@ void target_symbol::print (std::ostream& o) const void cast_op::print (std::ostream& o) const { + if (addressof) + o << "&"; o << base_name << '(' << *operand; o << ", " << lex_cast_qstring (type); if (module.length() > 0) diff --git a/staptree.h b/staptree.h index 7e9506bb..16f0256a 100644 --- a/staptree.h +++ b/staptree.h @@ -229,11 +229,12 @@ struct target_symbol: public symbol comp_struct_member, comp_literal_array_index }; + bool addressof; std::string base_name; std::vector > components; std::string probe_context_var; semantic_error* saved_conversion_error; - target_symbol(): saved_conversion_error (0) {} + target_symbol(): addressof(false), saved_conversion_error (0) {} void print (std::ostream& o) const; void visit (visitor* u); }; diff --git a/tapset-mark.cxx b/tapset-mark.cxx index 7544d7bb..4d8679d2 100644 --- a/tapset-mark.cxx +++ b/tapset-mark.cxx @@ -175,6 +175,9 @@ mark_var_expanding_visitor::visit_target_symbol (target_symbol* e) { assert(e->base_name.size() > 0 && e->base_name[0] == '$'); + if (e->addressof) + throw semantic_error("cannot take address of marker variable", e->tok); + if (e->base_name.substr(0,4) == "$arg") visit_target_symbol_arg (e); else if (e->base_name == "$format" || e->base_name == "$name") diff --git a/tapset-perfmon.cxx b/tapset-perfmon.cxx index e3f30ece..0fb567f7 100644 --- a/tapset-perfmon.cxx +++ b/tapset-perfmon.cxx @@ -64,6 +64,9 @@ perfmon_var_expanding_visitor::visit_target_symbol (target_symbol *e) if (e->base_name != "$counter") throw semantic_error ("target variables not available to perfmon probes"); + if (e->addressof) + throw semantic_error("cannot take address of perfmon variable", e->tok); + if (e->components.size() > 0) { switch (e->components[0].first) diff --git a/tapset-procfs.cxx b/tapset-procfs.cxx index 0c33857b..a996ee32 100644 --- a/tapset-procfs.cxx +++ b/tapset-procfs.cxx @@ -383,6 +383,9 @@ procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e) else if (! write_probe && ! lvalue) throw semantic_error("procfs $value variable cannot be read in a procfs read probe", e->tok); + if (e->addressof) + throw semantic_error("cannot take address of procfs variable", e->tok); + // Remember that we've seen a target variable. target_symbol_seen = true; diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx index 64f546e6..ec20282a 100644 --- a/tapset-utrace.cxx +++ b/tapset-utrace.cxx @@ -539,6 +539,9 @@ utrace_var_expanding_visitor::visit_target_symbol (target_symbol* e) throw semantic_error ("only \"process(PATH_OR_PID).syscall\" and \"process(PATH_OR_PID).syscall.return\" probes support target symbols", e->tok); + if (e->addressof) + throw semantic_error("cannot take address of utrace variable", e->tok); + if (e->base_name.substr(0,4) == "$arg") visit_target_symbol_arg(e); else if (e->base_name == "$syscall" || e->base_name == "$return") diff --git a/tapsets.cxx b/tapsets.cxx index 9ca25b0b..f629d08c 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2331,6 +2331,9 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e) if (dwarf_getscopes_die (scope_die, &scopes) == 0) return; + if (e->addressof) + throw semantic_error("cannot take address of context variable", e->tok); + target_symbol *tsym = new target_symbol; print_format* pf = new print_format; @@ -3356,6 +3359,9 @@ sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) { if (e->base_name == "$$name") { + if (e->addressof) + throw semantic_error("cannot take address of sdt variable", e->tok); + literal_string *myname = new literal_string (probe_name); myname->tok = e->tok; provide(myname); @@ -3409,6 +3415,9 @@ sdt_var_expanding_visitor::visit_target_symbol (target_symbol *e) if (e->components.empty()) { + if (e->addressof) + throw semantic_error("cannot take address of sdt variable", e->tok); + provide(fc); return; } @@ -5041,6 +5050,9 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) if (e->components.empty()) { + if (e->addressof) + throw semantic_error("cannot take address of tracepoint variable", e->tok); + // Just grab the value from the probe locals e->probe_context_var = "__tracepoint_arg_" + arg->name; e->type = pe_long; @@ -5140,6 +5152,9 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e) void tracepoint_var_expanding_visitor::visit_target_symbol_context (target_symbol* e) { + if (e->addressof) + throw semantic_error("cannot take address of context variable", e->tok); + if (is_active_lvalue (e)) throw semantic_error("write to tracepoint '" + e->base_name + "' not permitted", e->tok); diff --git a/testsuite/semko/target_addr1.stp b/testsuite/semko/target_addr1.stp new file mode 100755 index 00000000..cac3aab2 --- /dev/null +++ b/testsuite/semko/target_addr1.stp @@ -0,0 +1,6 @@ +#! stap -p2 + +// can't take the address of bitfields +probe kernel.function("release_task") { + println(& $p->did_exec) // unsigned:1 +} diff --git a/testsuite/semko/target_addr2.stp b/testsuite/semko/target_addr2.stp new file mode 100755 index 00000000..36133e3e --- /dev/null +++ b/testsuite/semko/target_addr2.stp @@ -0,0 +1,6 @@ +#! stap -p2 + +// can't take the address of register parameters +probe kernel.function("do_sys_open") { + println(& $dfd) +} diff --git a/testsuite/semko/target_addr3.stp b/testsuite/semko/target_addr3.stp new file mode 100755 index 00000000..fe072adb --- /dev/null +++ b/testsuite/semko/target_addr3.stp @@ -0,0 +1,6 @@ +#! stap -p2 + +// can't take the address of register return values +probe kernel.function("do_sys_open").return { + println(& $return) +} diff --git a/testsuite/semok/target_addr.stp b/testsuite/semok/target_addr.stp new file mode 100755 index 00000000..dfbc2606 --- /dev/null +++ b/testsuite/semok/target_addr.stp @@ -0,0 +1,11 @@ +#! stap -p2 + +// read the address of various task_struct members. +// all should roughly be $p + offsetof(foo) +probe kernel.function("release_task") { + println(& $p->state) // long + println(& $p->usage) // atomic_t + println(& $p->comm) // comm[TASK_COMM_LEN] + println(& $p->comm[1]) + println(& $p->parent) // task_struct* +} diff --git a/testsuite/systemtap.base/cast.exp b/testsuite/systemtap.base/cast.exp index 374132f0..38ef67b9 100644 --- a/testsuite/systemtap.base/cast.exp +++ b/testsuite/systemtap.base/cast.exp @@ -2,5 +2,6 @@ set test "cast" set ::result_string {PID OK PID2 OK execname OK -sa_data OK} +sa_data OK +usage OK} stap_run2 $srcdir/$subdir/$test.stp -g diff --git a/testsuite/systemtap.base/cast.stp b/testsuite/systemtap.base/cast.stp index e2505000..bb889bb8 100644 --- a/testsuite/systemtap.base/cast.stp +++ b/testsuite/systemtap.base/cast.stp @@ -33,6 +33,15 @@ probe begin else printf("sa_data %d != %d\n", data, cast_data) + // Compare usage counter values through a struct address + usage = @cast(curr, "task_struct")->usage->counter + pusage = & @cast(curr, "task_struct")->usage + cast_usage = @cast(pusage, "atomic_t")->counter + if (usage == cast_usage) + println("usage OK") + else + printf("usage %d != %d\n", usage, cast_usage) + exit() } -- cgit