summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2009-07-15 18:21:56 -0700
committerJosh Stone <jistone@redhat.com>2009-07-15 18:35:48 -0700
commit03c75a4a21ef3dba8abbc7e596d2a102427a3d96 (patch)
tree82e48a6a13454b9d0967b6d7e029aaf137ae47b9
parentaf4d5a48f2b0fed8b5a1bddda9bd1ffa81e7bd46 (diff)
downloadsystemtap-steved-03c75a4a21ef3dba8abbc7e596d2a102427a3d96.tar.gz
systemtap-steved-03c75a4a21ef3dba8abbc7e596d2a102427a3d96.tar.xz
systemtap-steved-03c75a4a21ef3dba8abbc7e596d2a102427a3d96.zip
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
-rw-r--r--dwflpp.cxx15
-rw-r--r--parse.cxx12
-rw-r--r--staptree.cxx4
-rw-r--r--staptree.h3
-rw-r--r--tapset-mark.cxx3
-rw-r--r--tapset-perfmon.cxx3
-rw-r--r--tapset-procfs.cxx3
-rw-r--r--tapset-utrace.cxx3
-rw-r--r--tapsets.cxx15
-rwxr-xr-xtestsuite/semko/target_addr1.stp6
-rwxr-xr-xtestsuite/semko/target_addr2.stp6
-rwxr-xr-xtestsuite/semko/target_addr3.stp6
-rwxr-xr-xtestsuite/semok/target_addr.stp11
-rw-r--r--testsuite/systemtap.base/cast.exp3
-rw-r--r--testsuite/systemtap.base/cast.stp9
15 files changed, 100 insertions, 2 deletions
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<target_symbol*>(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<std::pair<component_type, std::string> > 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()
}