This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[PATCH] Add new primitive @vma(address, module)
- From: "Yichun Zhang (agentzh)" <agentzh at gmail dot com>
- To: systemtap at sourceware dot org
- Cc: "Yichun Zhang (agentzh)" <agentzh at gmail dot com>
- Date: Fri, 24 Aug 2018 15:41:40 -0700
- Subject: [PATCH] Add new primitive @vma(address, module)
Implemented new primitive @vma(address, module) and @vma(address) to
return absolute virtual memory (VM) addresses from relative addresses
in the specified (ELF) module (or the current module in the probe
handler context). For non-PIE program modules, the relative address is
the absolute address and @vma() simply returns the value of the first
argument as-is.
It just exposes the existing VMA tracker facility to the stap language
level.
This is useful for accessing static variables in target processes with
DWARF-less probing (where @var() is not usable). It is also useful to
probe the addresses of literal C strings residing in the .rodata section
of the ELF files which cannot be addressed via the DWARF info or the
symbol table.
The dyninst runtime does not support the VMA tracker yet, but we still
cover its error messages in our tests cases. So once it does support it,
we can know it immediately through new failures in these test cases.
The newly added tests rely on the `nm` utility to find the (relative)
addresses of symbols in the ELF files of our trivial example C prgrams,
just like some of the existing tests in the official test suite.
---
dwflpp.cxx | 58 ++
dwflpp.h | 2 +
elaborate.cxx | 34 +
elaborate.h | 1 +
loc2stap.cxx | 54 +-
parse.cxx | 42 ++
staptree.cxx | 51 ++
staptree.h | 16 +
tapsets.cxx | 102 +++
testsuite/systemtap.base/at_vma.exp | 1146 ++++++++++++++++++++++++++++++++
testsuite/systemtap.base/at_vma_1.c | 5 +
testsuite/systemtap.base/at_vma_1.stp | 9 +
testsuite/systemtap.base/at_vma_10.stp | 8 +
testsuite/systemtap.base/at_vma_11.stp | 4 +
testsuite/systemtap.base/at_vma_12.stp | 12 +
testsuite/systemtap.base/at_vma_13.stp | 12 +
testsuite/systemtap.base/at_vma_14.c | 5 +
testsuite/systemtap.base/at_vma_14.stp | 3 +
testsuite/systemtap.base/at_vma_2.stp | 8 +
testsuite/systemtap.base/at_vma_3.stp | 5 +
testsuite/systemtap.base/at_vma_4.stp | 5 +
testsuite/systemtap.base/at_vma_5.stp | 9 +
testsuite/systemtap.base/at_vma_6.stp | 5 +
testsuite/systemtap.base/at_vma_7.stp | 5 +
testsuite/systemtap.base/at_vma_8.stp | 4 +
testsuite/systemtap.base/at_vma_9.stp | 8 +
translate.cxx | 8 +
27 files changed, 1568 insertions(+), 53 deletions(-)
create mode 100644 testsuite/systemtap.base/at_vma.exp
create mode 100644 testsuite/systemtap.base/at_vma_1.c
create mode 100644 testsuite/systemtap.base/at_vma_1.stp
create mode 100644 testsuite/systemtap.base/at_vma_10.stp
create mode 100644 testsuite/systemtap.base/at_vma_11.stp
create mode 100644 testsuite/systemtap.base/at_vma_12.stp
create mode 100644 testsuite/systemtap.base/at_vma_13.stp
create mode 100644 testsuite/systemtap.base/at_vma_14.c
create mode 100644 testsuite/systemtap.base/at_vma_14.stp
create mode 100644 testsuite/systemtap.base/at_vma_2.stp
create mode 100644 testsuite/systemtap.base/at_vma_3.stp
create mode 100644 testsuite/systemtap.base/at_vma_4.stp
create mode 100644 testsuite/systemtap.base/at_vma_5.stp
create mode 100644 testsuite/systemtap.base/at_vma_6.stp
create mode 100644 testsuite/systemtap.base/at_vma_7.stp
create mode 100644 testsuite/systemtap.base/at_vma_8.stp
create mode 100644 testsuite/systemtap.base/at_vma_9.stp
diff --git a/dwflpp.cxx b/dwflpp.cxx
index 2172e705a..a66fb99e7 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -3088,6 +3088,64 @@ dwflpp::pc_location_as_function_string(Dwarf_Addr pc)
return locstr;
}
+expression *
+dwflpp::translate_address(Dwarf_Addr addr, const token *tok)
+{
+ int n = dwfl_module_relocations (module);
+ Dwarf_Addr reloc_addr = addr;
+ const char *secname = "";
+
+ if (n > 1)
+ {
+ int i = dwfl_module_relocate_address (module, &reloc_addr);
+ secname = dwfl_module_relocation_info (module, i, NULL);
+ }
+
+ if (n > 0 && !(n == 1 && secname == NULL))
+ {
+ std::string c;
+
+ if (n > 1 || secname[0] != 0)
+ {
+ // This gives us the module name and section name within the
+ // module, for a kernel module.
+ c = "({ unsigned long addr = 0; "
+ "addr = _stp_kmodule_relocate (\""
+ + module_name + "\", \"" + secname + "\", "
+ + lex_cast_hex (reloc_addr)
+ + "); addr; })";
+ }
+ else if (n == 1 && module_name == "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.
+ c = "({ unsigned long addr = 0; "
+ "addr = _stp_kmodule_relocate (\"kernel\", \"_stext\", "
+ + lex_cast_hex (addr - sess.sym_stext)
+ + "); addr; })";
+ }
+ else
+ {
+ c = "/* pragma:vma */ "
+ "({ unsigned long addr = 0; "
+ "addr = _stp_umodule_relocate (\""
+ + path_remove_sysroot(sess,
+ resolve_path(module_name.c_str()))
+ + "\", "
+ + lex_cast_hex (addr)
+ + ", current); addr; })";
+ }
+
+ embedded_expr *r = new embedded_expr;
+ r->tok = tok;
+ r->code = c;
+ return r;
+ }
+ else
+ return new literal_number(addr);
+}
+
struct location *
dwflpp::translate_location(location_context *ctx,
Dwarf_Attribute *attr, Dwarf_Die *die,
diff --git a/dwflpp.h b/dwflpp.h
index 998b96e7d..cde1d0d10 100644
--- a/dwflpp.h
+++ b/dwflpp.h
@@ -493,6 +493,8 @@ struct dwflpp
Dwarf_Addr relocate_address(Dwarf_Addr addr, interned_string& reloc_section);
+ expression *translate_address(Dwarf_Addr addr, const token *tok);
+
void resolve_unqualified_inner_typedie (Dwarf_Die *typedie,
Dwarf_Die *innerdie,
const target_symbol *e);
diff --git a/elaborate.cxx b/elaborate.cxx
index c55818f02..b72cda173 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -3267,6 +3267,11 @@ struct assignment_symbol_fetcher
sym = NULL;
}
+ void visit_atvma_op (atvma_op*)
+ {
+ sym = NULL;
+ }
+
void visit_cast_op (cast_op*)
{
sym = NULL;
@@ -5589,6 +5594,7 @@ struct initial_typeresolution_info : public typeresolution_info
// and not all substitutions are done, replace the functions that throw errors.
void visit_target_symbol (target_symbol*) {}
void visit_atvar_op (atvar_op*) {}
+ void visit_atvma_op (atvma_op*) {}
void visit_defined_op (defined_op*) {}
void visit_entry_op (entry_op*) {}
void visit_cast_op (cast_op*) {}
@@ -6390,6 +6396,34 @@ typeresolution_info::visit_atvar_op (atvar_op* e)
void
+typeresolution_info::visit_atvma_op (atvma_op* e)
+{
+ if (session.verbose > 2)
+ {
+ clog << _("Resolution problem with ");
+ if (current_function)
+ {
+ clog << "function " << current_function->name << endl;
+ current_function->body->print (clog);
+ clog << endl;
+ }
+ else if (current_probe)
+ {
+ clog << "probe " << *current_probe->sole_location() << endl;
+ current_probe->body->print (clog);
+ clog << endl;
+ }
+ else
+ //TRANSLATORS: simply saying not an issue with a probe or function
+ clog << _("other") << endl;
+ }
+
+ //clog << "expr: " << *e << endl;
+ throw SEMANTIC_ERROR(_("unresolved @vma() expression"), e->tok);
+}
+
+
+void
typeresolution_info::visit_defined_op (defined_op* e)
{
// PR18079: if a @defined is still around, it may have a parameter that
diff --git a/elaborate.h b/elaborate.h
index 98754ece5..90ad94a6a 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -163,6 +163,7 @@ struct typeresolution_info: public visitor
void visit_cast_op (cast_op* e);
void visit_autocast_op (autocast_op* e);
void visit_atvar_op (atvar_op* e);
+ void visit_atvma_op (atvma_op* e);
void visit_defined_op (defined_op* e);
void visit_entry_op (entry_op* e);
void visit_perf_op (perf_op* e);
diff --git a/loc2stap.cxx b/loc2stap.cxx
index b73036c2f..5958e7ee0 100644
--- a/loc2stap.cxx
+++ b/loc2stap.cxx
@@ -68,59 +68,7 @@ location_context::translate_address(Dwarf_Addr addr)
if (dw == NULL)
return new literal_number(addr);
- int n = dwfl_module_relocations (dw->module);
- Dwarf_Addr reloc_addr = addr;
- const char *secname = "";
-
- if (n > 1)
- {
- int i = dwfl_module_relocate_address (dw->module, &reloc_addr);
- secname = dwfl_module_relocation_info (dw->module, i, NULL);
- }
-
- if (n > 0 && !(n == 1 && secname == NULL))
- {
- std::string c;
-
- if (n > 1 || secname[0] != 0)
- {
- // This gives us the module name and section name within the
- // module, for a kernel module.
- c = "({ unsigned long addr = 0; "
- "addr = _stp_kmodule_relocate (\""
- + dw->module_name + "\", \"" + secname + "\", "
- + lex_cast_hex (reloc_addr)
- + "); addr; })";
- }
- else if (n == 1 && dw->module_name == "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.
- c = "({ unsigned long addr = 0; "
- "addr = _stp_kmodule_relocate (\"kernel\", \"_stext\", "
- + lex_cast_hex (addr - dw->sess.sym_stext)
- + "); addr; })";
- }
- else
- {
- c = "/* pragma:vma */ "
- "({ unsigned long addr = 0; "
- "addr = _stp_umodule_relocate (\""
- + path_remove_sysroot(dw->sess,
- resolve_path(dw->module_name.c_str()))
- + "\", "
- + lex_cast_hex (addr)
- + ", current); addr; })";
- }
-
- embedded_expr *r = new embedded_expr;
- r->tok = e->tok;
- r->code = c;
- return r;
- }
- else
- return new literal_number(addr);
+ return dw->translate_address(addr, e->tok);
}
location *
diff --git a/parse.cxx b/parse.cxx
index 751f56add..2fbcb623f 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -204,6 +204,7 @@ private: // nonterminals
target_symbol *parse_target_symbol ();
cast_op *parse_cast_op ();
atvar_op *parse_atvar_op ();
+ atvma_op *parse_atvma_op ();
expression* parse_entry_op (const token* t);
expression* parse_defined_op (const token* t);
expression* parse_const_op (const token* t);
@@ -3690,6 +3691,14 @@ parser::parse_dwarf_value ()
expr = tsym = parse_cast_op ();
else if (tok_is (t, tok_operator, "@var"))
expr = tsym = parse_atvar_op ();
+ else if (tok_is (t, tok_operator, "@vma"))
+ {
+ expr = parse_atvma_op ();
+ if (addressof)
+ {
+ throw PARSE_ERROR (_("cannot take address of @vma"), addrtok);
+ }
+ }
else if (addressof && !input.has_version("2.6"))
// '&' on old version only allowed specific target_symbol types
throw PARSE_ERROR (_("expected @cast, @var or $var"));
@@ -4148,6 +4157,39 @@ atvar_op* parser::parse_atvar_op ()
}
+// Parse a @vma.
+atvma_op* parser::parse_atvma_op ()
+{
+ const token* t = next ();
+ if (t->type == tok_operator && t->content == "@vma")
+ {
+ atvma_op *vop = new atvma_op;
+ int64_t address;
+ vop->tok = t;
+ expect_op ("(");
+ expect_number (address);
+ vop->address = (uint64_t) address;
+ if (peek_op (","))
+ {
+ swallow ();
+ t = next ();
+ if (!t || t->type != tok_string)
+ throw PARSE_ERROR (_("expected string"));
+ vop->module = t->content;
+ if (vop->module.find(":") != string::npos)
+ throw PARSE_ERROR (_("@vma() cannot take multiple module values"),
+ t);
+ swallow ();
+ }
+ else
+ vop->module = "";
+ expect_op (")");
+ return vop;
+ }
+
+ throw PARSE_ERROR (_("expected @vma"));
+}
+
// Parse a @defined(). Given head token has already been consumed.
expression* parser::parse_defined_op (const token* t)
{
diff --git a/staptree.cxx b/staptree.cxx
index d1193e336..275b89912 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -529,6 +529,15 @@ void atvar_op::print (ostream& o) const
}
+void atvma_op::print (ostream& o) const
+{
+ o << "@vma(" << lex_cast_hex(address);
+ if (module.length() > 0)
+ o << ", " << lex_cast_qstring (module);
+ o << ')';
+}
+
+
void cast_op::print (ostream& o) const
{
if (addressof)
@@ -1761,6 +1770,13 @@ atvar_op::visit (visitor* u)
void
+atvma_op::visit (visitor* u)
+{
+ u->visit_atvma_op(this);
+}
+
+
+void
defined_op::visit (visitor* u)
{
u->visit_defined_op(this);
@@ -2141,6 +2157,11 @@ traversing_visitor::visit_atvar_op (atvar_op* e)
}
void
+traversing_visitor::visit_atvma_op (atvma_op*)
+{
+}
+
+void
traversing_visitor::visit_defined_op (defined_op* e)
{
e->operand->visit (this);
@@ -2403,6 +2424,13 @@ expression_visitor::visit_atvar_op (atvar_op* e)
}
void
+expression_visitor::visit_atvma_op (atvma_op* e)
+{
+ traversing_visitor::visit_atvma_op (e);
+ visit_expression (e);
+}
+
+void
expression_visitor::visit_defined_op (defined_op* e)
{
traversing_visitor::visit_defined_op (e);
@@ -2682,6 +2710,11 @@ varuse_collecting_visitor::visit_atvar_op (atvar_op *e)
functioncall_traversing_visitor::visit_atvar_op (e);
}
+void
+varuse_collecting_visitor::visit_atvma_op (atvma_op *)
+{
+ // No need to call the base op, we've done everything here.
+}
void
varuse_collecting_visitor::visit_cast_op (cast_op *e)
@@ -3210,6 +3243,12 @@ throwing_visitor::visit_atvar_op (atvar_op* e)
}
void
+throwing_visitor::visit_atvma_op (atvma_op* e)
+{
+ throwone (e->tok);
+}
+
+void
throwing_visitor::visit_cast_op (cast_op* e)
{
throwone (e->tok);
@@ -3551,6 +3590,12 @@ update_visitor::visit_atvar_op (atvar_op* e)
}
void
+update_visitor::visit_atvma_op (atvma_op* e)
+{
+ provide (e);
+}
+
+void
update_visitor::visit_defined_op (defined_op* e)
{
replace (e->operand);
@@ -3845,6 +3890,12 @@ deep_copy_visitor::visit_atvar_op (atvar_op* e)
}
void
+deep_copy_visitor::visit_atvma_op (atvma_op* e)
+{
+ update_visitor::visit_atvma_op(new atvma_op(*e));
+}
+
+void
deep_copy_visitor::visit_defined_op (defined_op* e)
{
update_visitor::visit_defined_op(new defined_op(*e));
diff --git a/staptree.h b/staptree.h
index 00c22f9f1..90c6bab52 100644
--- a/staptree.h
+++ b/staptree.h
@@ -420,6 +420,14 @@ struct atvar_op: public target_symbol
void visit (visitor* u);
};
+struct atvma_op: public expression
+{
+ interned_string module;
+ uint64_t address;
+ void print (std::ostream& o) const;
+ void visit (visitor* u);
+};
+
struct defined_op: public expression
{
expression *operand;
@@ -967,6 +975,7 @@ struct visitor
virtual void visit_cast_op (cast_op* e) = 0;
virtual void visit_autocast_op (autocast_op* e) = 0;
virtual void visit_atvar_op (atvar_op* e) = 0;
+ virtual void visit_atvma_op (atvma_op* e) = 0;
virtual void visit_defined_op (defined_op* e) = 0;
virtual void visit_entry_op (entry_op* e) = 0;
virtual void visit_perf_op (perf_op* e) = 0;
@@ -1020,6 +1029,7 @@ struct nop_visitor: public visitor
virtual void visit_cast_op (cast_op*) {};
virtual void visit_autocast_op (autocast_op*) {};
virtual void visit_atvar_op (atvar_op*) {};
+ virtual void visit_atvma_op (atvma_op*) {};
virtual void visit_defined_op (defined_op*) {};
virtual void visit_entry_op (entry_op*) {};
virtual void visit_perf_op (perf_op*) {};
@@ -1073,6 +1083,7 @@ struct traversing_visitor: public visitor
void visit_cast_op (cast_op* e);
void visit_autocast_op (autocast_op* e);
void visit_atvar_op (atvar_op* e);
+ void visit_atvma_op (atvma_op* e);
void visit_defined_op (defined_op* e);
void visit_entry_op (entry_op* e);
void visit_perf_op (perf_op* e);
@@ -1113,6 +1124,7 @@ struct expression_visitor: public traversing_visitor
void visit_cast_op (cast_op* e);
void visit_autocast_op (autocast_op* e);
void visit_atvar_op (atvar_op* e);
+ void visit_atvma_op (atvma_op* e);
void visit_defined_op (defined_op* e);
void visit_entry_op (entry_op* e);
void visit_perf_op (perf_op* e);
@@ -1175,6 +1187,7 @@ struct varuse_collecting_visitor: public functioncall_traversing_visitor
void visit_cast_op (cast_op* e);
void visit_autocast_op (autocast_op* e);
void visit_atvar_op (atvar_op *e);
+ void visit_atvma_op (atvma_op* e);
void visit_defined_op (defined_op* e);
void visit_entry_op (entry_op* e);
void visit_perf_op (perf_op* e);
@@ -1236,6 +1249,7 @@ struct throwing_visitor: public visitor
void visit_cast_op (cast_op* e);
void visit_autocast_op (autocast_op* e);
void visit_atvar_op (atvar_op* e);
+ void visit_atvma_op (atvma_op* e);
void visit_defined_op (defined_op* e);
void visit_entry_op (entry_op* e);
void visit_perf_op (perf_op* e);
@@ -1350,6 +1364,7 @@ struct update_visitor: public visitor
virtual void visit_cast_op (cast_op* e);
virtual void visit_autocast_op (autocast_op* e);
virtual void visit_atvar_op (atvar_op* e);
+ virtual void visit_atvma_op (atvma_op* e);
virtual void visit_defined_op (defined_op* e);
virtual void visit_entry_op (entry_op* e);
virtual void visit_perf_op (perf_op* e);
@@ -1418,6 +1433,7 @@ struct deep_copy_visitor: public update_visitor
virtual void visit_cast_op (cast_op* e);
virtual void visit_autocast_op (autocast_op* e);
virtual void visit_atvar_op (atvar_op* e);
+ virtual void visit_atvma_op (atvma_op* e);
virtual void visit_defined_op (defined_op* e);
virtual void visit_entry_op (entry_op* e);
virtual void visit_perf_op (perf_op* e);
diff --git a/tapsets.cxx b/tapsets.cxx
index ae6cfd83f..12b4e3a85 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -2857,6 +2857,7 @@ struct dwarf_var_expanding_visitor: public var_expanding_visitor
void visit_target_symbol_context (target_symbol* e);
void visit_target_symbol (target_symbol* e);
void visit_atvar_op (atvar_op* e);
+ void visit_atvma_op (atvma_op* e);
void visit_cast_op (cast_op* e);
void visit_entry_op (entry_op* e);
void visit_perf_op (perf_op* e);
@@ -4437,6 +4438,17 @@ dwarf_var_expanding_visitor::visit_atvar_op (atvar_op *e)
void
+dwarf_var_expanding_visitor::visit_atvma_op (atvma_op *e)
+{
+ // Fill in our current module context if needed
+ if (e->module.empty())
+ e->module = q.dw.module_name;
+
+ var_expanding_visitor::visit_atvma_op(e);
+}
+
+
+void
dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
{
assert(e->name.size() > 0 && (e->name[0] == '$' || e->name == "@var"));
@@ -5137,6 +5149,93 @@ dwarf_atvar_expanding_visitor::visit_atvar_op (atvar_op* e)
}
+struct dwarf_atvma_expanding_visitor: public var_expanding_visitor
+{
+ dwarf_builder& db;
+
+ dwarf_atvma_expanding_visitor(systemtap_session& s, dwarf_builder& db):
+ var_expanding_visitor(s), db(db) {}
+ void visit_atvma_op (atvma_op* e);
+};
+
+
+struct dwarf_atvma_query: public base_query
+{
+ atvma_op& e;
+ const bool userspace_p;
+ bool &found;
+
+ dwarf_atvma_query(dwflpp& dw, const string& module, atvma_op& e,
+ const bool userspace_p, bool &found):
+ base_query(dw, module), e(e),
+ userspace_p(userspace_p), found(found) {}
+
+ void handle_query_module ();
+ void query_library (const char *) {}
+ void query_plt (const char *, size_t) {}
+};
+
+
+void
+dwarf_atvma_query::handle_query_module ()
+{
+ found = true;
+}
+
+
+void
+dwarf_atvma_expanding_visitor::visit_atvma_op (atvma_op* e)
+{
+ const bool lvalue = is_active_lvalue(e);
+ if (lvalue)
+ throw SEMANTIC_ERROR(_("writing to @vma variable not permitted"), e->tok);
+
+ if (e->module.empty())
+ e->module = "kernel";
+
+ bool found_module = false;
+
+ bool userspace_p = false;
+
+ // @vma() does not allow multiple modules separated by ':'.
+ // we check this in the parser.
+ string module = e->module;
+
+ dwflpp* dw;
+ userspace_p = is_user_module(module);
+ if (!userspace_p)
+ {
+ // kernel or kernel module target
+ dw = db.get_kern_dw(sess, module);
+ }
+ else
+ {
+ module = find_executable(module, "", sess.sysenv);
+ dw = db.get_user_dw(sess, module);
+ }
+
+ dwarf_atvma_query q (*dw, module, *e, userspace_p, found_module);
+ dw->iterate_over_modules<base_query>(&query_module, &q);
+
+ if (found_module)
+ {
+ sess.unwindsym_modules.insert(module);
+
+ expression* result = dw->translate_address(e->address, e->tok);
+
+ if (result)
+ {
+ result->visit(this);
+ return;
+ }
+ }
+
+ throw SEMANTIC_ERROR (_F("unable to find module '%s'", module.c_str()),
+ e->tok);
+ provide(e);
+}
+
+
void
dwarf_derived_probe::printsig (ostream& o) const
{
@@ -5835,6 +5934,9 @@ dwarf_derived_probe::register_patterns(systemtap_session& s)
filter = new dwarf_atvar_expanding_visitor(s, *dw);
s.code_filters.push_back(filter);
+ filter = new dwarf_atvma_expanding_visitor(s, *dw);
+ s.code_filters.push_back(filter);
+
register_function_and_statement_variants(s, root->bind(TOK_KERNEL), dw, pr_privileged);
register_function_and_statement_variants(s, root->bind_str(TOK_MODULE), dw, pr_privileged);
root->bind(TOK_KERNEL)->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)
diff --git a/testsuite/systemtap.base/at_vma.exp b/testsuite/systemtap.base/at_vma.exp
new file mode 100644
index 000000000..89ecd09aa
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma.exp
@@ -0,0 +1,1146 @@
+set test "at_vma"
+set testpath "$srcdir/$subdir"
+
+if {! [installtest_p]} { untested "$test"; return }
+if {! [uretprobes_p]} { untested "$test"; return }
+
+# --- TEST 1 ---
+
+set subtest1 "TEST 1: @vma - not PIE - in func - explicit module"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest1: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_1.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set cwd [pwd]
+ regsub -all -- {\$\^PWD\y} $stp_src $cwd stp_src
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest1: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest1: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_1.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest1 ($runtime)"
+
+ set cmd "stap --runtime=$runtime -c ./a.out './${test}_1.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ set exp_out "0xbeefdead\n1\n"
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+
+ if {$failed} {
+ fail "${test_name}: exit code not zero"
+ } else {
+ pass "${test_name}: exit code is zero"
+ }
+ if {$stderr ne ""} {
+ send_log "stderr:\n$stderr"
+ }
+ }
+}
+
+# --- TEST 2 ---
+
+set subtest2 "TEST 2: @vma - not PIE - in func - no module"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest2: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_2.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest2: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest2: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_2.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ set test_name "$test: $subtest2"
+
+ set cmd "stap -c ./a.out './${test}_2.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ set exp_out "0x0\n"
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+
+ if {$failed} {
+ fail "${test_name}: exit code not zero"
+ } else {
+ pass "${test_name}: exit code is zero"
+ }
+ if {$stderr ne ""} {
+ send_log "stderr:\n$stderr"
+ }
+}
+
+# --- TEST 3 ---
+
+set subtest3 "TEST 3: @vma - not PIE - in probe - explicit module"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest3: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_3.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set cwd [pwd]
+ regsub -all -- {\$\^PWD\y} $stp_src $cwd stp_src
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest3: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest3: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_3.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest3 ($runtime)"
+
+ set cmd "stap --runtime=$runtime -c ./a.out './${test}_3.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ set exp_out "0xbeefdead\n1\n"
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+
+ if {$failed} {
+ fail "${test_name}: exit code not zero"
+ } else {
+ pass "${test_name}: exit code is zero"
+ }
+ if {$stderr ne ""} {
+ send_log "stderr:\n$stderr"
+ }
+ }
+}
+
+# --- TEST 4 ---
+
+set subtest4 "TEST 4: @vma - not PIE - in probe - no module arg"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest4: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_4.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set cwd [pwd]
+ regsub -all -- {\$\^PWD\y} $stp_src $cwd stp_src
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest4: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest4: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_4.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest4 ($runtime)"
+
+ set cmd "stap --runtime=$runtime -c ./a.out './${test}_4.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ set exp_out "0xbeefdead\n1\n"
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+
+ if {$failed} {
+ fail "${test_name}: exit code not zero"
+ } else {
+ pass "${test_name}: exit code is zero"
+ }
+ if {$stderr ne ""} {
+ send_log "stderr:\n$stderr"
+ }
+ }
+}
+
+# --- TEST 5 ---
+
+set subtest5 "TEST 5: @vma - PIE - in func - explicit module"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g additional_flags=-fpic additional_flags=-pie"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest5: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_5.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set cwd [pwd]
+ regsub -all -- {\$\^PWD\y} $stp_src $cwd stp_src
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest5: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest5: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_5.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest5 ($runtime)"
+
+ set cmd "stap --runtime=$runtime -c ./a.out './${test}_5.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ if {$runtime eq "dyninst"} {
+ set exp_out ""
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+ } else {
+ set exp_out "0\n0xbeefdead\n"
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+ }
+ if {$runtime eq "dyninst"} {
+
+ if {$failed} {
+ pass "${test_name}: exit code should be non-zero"
+ } else {
+ fail "${test_name}: exit code should be non-zero but is zero"
+ }
+
+ set stderr_pat "semantic error: VMA-tracking is only supported by the kernel runtime \\(PR15052\\): operator '\\@vma' at .*?\\.stp:2:20"
+ regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat
+ if {[regexp -linestop -- $stderr_pat $stderr]} {
+ pass "${test_name}: stderr matches \"$escaped_stderr_pat\""
+ } else {
+ fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\""
+ }
+
+ } else {
+ if {$failed} {
+ fail "${test_name}: exit code not zero"
+ } else {
+ pass "${test_name}: exit code is zero"
+ }
+ }
+ }
+}
+
+# --- TEST 6 ---
+
+set subtest6 "TEST 6: @vma - PIE - in probe - explicit module"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g additional_flags=-fpic additional_flags=-pie"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest6: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_6.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set cwd [pwd]
+ regsub -all -- {\$\^PWD\y} $stp_src $cwd stp_src
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest6: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest6: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_6.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest6 ($runtime)"
+
+ set cmd "stap --runtime=$runtime -c ./a.out './${test}_6.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ if {$runtime eq "dyninst"} {
+ set exp_out ""
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+ } else {
+ set exp_out "0xbeefdead\n0\n"
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+ }
+ if {$runtime eq "dyninst"} {
+
+ if {$failed} {
+ pass "${test_name}: exit code should be non-zero"
+ } else {
+ fail "${test_name}: exit code should be non-zero but is zero"
+ }
+
+ set stderr_pat "semantic error: VMA-tracking is only supported by the kernel runtime \\(PR15052\\): operator '\\@vma' at .*?\\.stp:2:31"
+ regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat
+ if {[regexp -linestop -- $stderr_pat $stderr]} {
+ pass "${test_name}: stderr matches \"$escaped_stderr_pat\""
+ } else {
+ fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\""
+ }
+
+ } else {
+ if {$failed} {
+ fail "${test_name}: exit code not zero"
+ } else {
+ pass "${test_name}: exit code is zero"
+ }
+ }
+ }
+}
+
+# --- TEST 7 ---
+
+set subtest7 "TEST 7: @vma - PIE - in probe - no module arg"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g additional_flags=-fpic additional_flags=-pie"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest7: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_7.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest7: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest7: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_7.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest7 ($runtime)"
+
+ set cmd "stap --runtime=$runtime -c ./a.out './${test}_7.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ if {$runtime eq "dyninst"} {
+ set exp_out ""
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+ } else {
+ set exp_out "0xbeefdead\n0\n"
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+ }
+ if {$runtime eq "dyninst"} {
+
+ if {$failed} {
+ pass "${test_name}: exit code should be non-zero"
+ } else {
+ fail "${test_name}: exit code should be non-zero but is zero"
+ }
+
+ set stderr_pat "semantic error: VMA-tracking is only supported by the kernel runtime \\(PR15052\\): operator '\\@vma' at .*?\\.stp:2:31"
+ regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat
+ if {[regexp -linestop -- $stderr_pat $stderr]} {
+ pass "${test_name}: stderr matches \"$escaped_stderr_pat\""
+ } else {
+ fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\""
+ }
+
+ } else {
+ if {$failed} {
+ fail "${test_name}: exit code not zero"
+ } else {
+ pass "${test_name}: exit code is zero"
+ }
+ }
+ }
+}
+
+# --- TEST 8 ---
+
+set subtest8 "TEST 8: take address of @vma"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g additional_flags=-fpic additional_flags=-pie"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest8: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_8.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest8: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest8: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_8.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest8 ($runtime)"
+
+ set cmd "stap --runtime=$runtime -c ./a.out './${test}_8.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ set exp_out ""
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+
+ if {$failed} {
+ pass "${test_name}: exit code should be non-zero"
+ } else {
+ fail "${test_name}: exit code should be non-zero but is zero"
+ }
+
+ set stderr_pat "parse error: cannot take address of \\@vma\n\\s+at: operator '\\&' at .*?\\.stp:2:20\$"
+ regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat
+ if {[regexp -lineanchor -- $stderr_pat $stderr]} {
+ pass "${test_name}: stderr matches \"$escaped_stderr_pat\""
+ } else {
+ fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\""
+ }
+ }
+}
+
+# --- TEST 9 ---
+
+set subtest9 "TEST 9: @vma - multiple module values separated by :"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest9: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_9.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set cwd [pwd]
+ regsub -all -- {\$\^PWD\y} $stp_src $cwd stp_src
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest9: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest9: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_9.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest9 ($runtime)"
+
+ set cmd "stap --runtime=$runtime -c ./a.out './${test}_9.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ set exp_out ""
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+
+ if {$failed} {
+ pass "${test_name}: exit code should be non-zero"
+ } else {
+ fail "${test_name}: exit code should be non-zero but is zero"
+ }
+
+ set stderr_pat "\\yparse error: \\@vma\\(\\) cannot take multiple module values\n\\s+at: string '\[^'\\n\]*?/a\\.out:\[^'\\n\]*?/a\\.out' at .*?\\.stp:2:47\n"
+ regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat
+ if {[regexp -lineanchor -- $stderr_pat $stderr]} {
+ pass "${test_name}: stderr matches \"$escaped_stderr_pat\""
+ } else {
+ fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\""
+ }
+ }
+}
+
+# --- TEST 10 ---
+
+set subtest10 "TEST 10: @vma - print - with module"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest10: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_10.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set cwd [pwd]
+ regsub -all -- {\$\^PWD\y} $stp_src $cwd stp_src
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest10: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest10: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_10.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest10 ($runtime)"
+
+ set cmd "stap -p1 --runtime=$runtime -c ./a.out './${test}_10.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ set out_pat "\\yreturn user_long\\(\\@vma\\(0x\[0-9a-f\]+, \"\[^\\n\"\]*?/a\\.out\"\\)\\);\$"
+ regsub -all -- {\n} $out_pat {\n} escaped_out_pat
+ if {[regexp -lineanchor -- $out_pat $out]} {
+ pass "${test_name}: stdout matches \"$escaped_out_pat\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_out_pat\": got \"$out\""
+ }
+
+ if {$failed} {
+ fail "${test_name}: exit code not zero"
+ } else {
+ pass "${test_name}: exit code is zero"
+ }
+ if {$stderr ne ""} {
+ send_log "stderr:\n$stderr"
+ }
+ }
+}
+
+# --- TEST 11 ---
+
+set subtest11 "TEST 11: @vma - print - without module"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest11: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_11.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest11: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest11: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_11.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest11 ($runtime)"
+
+ set cmd "stap -p1 --runtime=$runtime -c ./a.out './${test}_11.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ set out_pat ", user_long\\(\\@vma\\(0x\[0-9a-f\]+\\)\\)\\);\$"
+ regsub -all -- {\n} $out_pat {\n} escaped_out_pat
+ if {[regexp -lineanchor -- $out_pat $out]} {
+ pass "${test_name}: stdout matches \"$escaped_out_pat\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_out_pat\": got \"$out\""
+ }
+
+ if {$failed} {
+ fail "${test_name}: exit code not zero"
+ } else {
+ pass "${test_name}: exit code is zero"
+ }
+ if {$stderr ne ""} {
+ send_log "stderr:\n$stderr"
+ }
+ }
+}
+
+# --- TEST 12 ---
+
+set subtest12 "TEST 12: @vma - not PIE - in func - explicit module - no DWARF"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest12: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_12.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set cwd [pwd]
+ regsub -all -- {\$\^PWD\y} $stp_src $cwd stp_src
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest12: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest12: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_12.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest12 ($runtime)"
+
+ set cmd "stap --runtime=$runtime -c ./a.out './${test}_12.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ set exp_out "0xbeefdead\nno var v found\n1\n"
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+
+ if {$failed} {
+ fail "${test_name}: exit code not zero"
+ } else {
+ pass "${test_name}: exit code is zero"
+ }
+ if {$stderr ne ""} {
+ send_log "stderr:\n$stderr"
+ }
+ }
+}
+
+# --- TEST 13 ---
+
+set subtest13 "TEST 13: @vma - PIE - in func - explicit module - no DWARF"
+
+set res [target_compile ${testpath}/${test}_1.c ./a.out executable \
+ "additional_flags=-O additional_flags=-fpic additional_flags=-pie"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest13: unable to compile ${test}_1.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_13.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set cwd [pwd]
+ regsub -all -- {\$\^PWD\y} $stp_src $cwd stp_src
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest13: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest13: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_13.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest13 ($runtime)"
+
+ set cmd "stap --runtime=$runtime -c ./a.out './${test}_13.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ if {$runtime eq "dyninst"} {
+ set exp_out ""
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+ } else {
+ set exp_out "no var v found\n0\n0xbeefdead\n"
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+ }
+ if {$runtime eq "dyninst"} {
+
+ if {$failed} {
+ pass "${test_name}: exit code should be non-zero"
+ } else {
+ fail "${test_name}: exit code should be non-zero but is zero"
+ }
+
+ set stderr_pat "semantic error: VMA-tracking is only supported by the kernel runtime \\(PR15052\\): operator '\\@vma' at .*?\\.stp:2:20"
+ regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat
+ if {[regexp -linestop -- $stderr_pat $stderr]} {
+ pass "${test_name}: stderr matches \"$escaped_stderr_pat\""
+ } else {
+ fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\""
+ }
+
+ } else {
+ if {$failed} {
+ fail "${test_name}: exit code not zero"
+ } else {
+ pass "${test_name}: exit code is zero"
+ }
+ }
+ }
+}
+
+# --- TEST 14 ---
+
+set subtest14 "TEST 14: @vma cannot be used as an lvalue"
+
+set res [target_compile ${testpath}/${test}_14.c ./a.out executable \
+ "additional_flags=-O additional_flags=-g"]
+if {$res ne ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test: $subtest14: unable to compile ${test}_14.c"
+} else {
+ set stp_fh [open "$srcdir/$subdir/${test}_14.stp" r]
+ set stp_src [read $stp_fh]
+ close $stp_fh
+
+ set nm_fh [open "| nm --defined-only ./a.out" r]
+ set found 0
+ while {[gets $nm_fh line] >= 0} {
+ if {[regexp -- {^\s*([0-9a-f]+)\s+[DT]\s+v\s*$} $line match addr]} {
+ send_log "found symbol 'v' at addr $addr in the nm output\n"
+ regsub -all -- {\$\^ADDR_v\y} $stp_src $addr stp_src
+ set found 1
+ break
+ }
+ }
+
+ if {[catch {close $nm_fh} nm_err] != 0} {
+ fail "$test: $subtest14: failed to run nm: $nm_err"
+ return
+ }
+
+ if {! $found} {
+ fail "$test: $subtest14: symbol 'v' not found in executable ./a.out"
+ return
+ }
+ set stp_fh [open "./${test}_14.stp" w+]
+ puts -nonewline $stp_fh $stp_src
+ close $stp_fh
+
+ foreach runtime [get_runtime_list] {
+ if {$runtime eq ""} {
+ set runtime "kernel"
+ }
+ set test_name "$test: $subtest14 ($runtime)"
+
+ set cmd "stap --runtime=$runtime -c ./a.out './${test}_14.stp'"
+ send_log "executing: $cmd\n"
+ set pipe [open "| sh -c {$cmd}" r]
+ set out [read $pipe]
+ set failed 0
+ if {[catch {close $pipe} stderr] != 0} {
+ set failed 1
+ }
+
+ set exp_out ""
+ regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+ if {$out eq $exp_out} {
+ pass "${test_name}: stdout matches \"$escaped_exp_out\""
+ } else {
+ fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+ }
+
+ if {$failed} {
+ pass "${test_name}: exit code should be non-zero"
+ } else {
+ fail "${test_name}: exit code should be non-zero but is zero"
+ }
+
+ set stderr_pat "^semantic error: writing to \\@vma variable not permitted: operator '\\@vma' at \[^\\n\]*?\\.stp:2:5\\n source: \\@vma\\(0x0000000000601020\\) = 32;\\n \\^\\n"
+ regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat
+ if {[regexp -linestop -- $stderr_pat $stderr]} {
+ pass "${test_name}: stderr matches \"$escaped_stderr_pat\""
+ } else {
+ fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\""
+ }
+ }
+}
diff --git a/testsuite/systemtap.base/at_vma_1.c b/testsuite/systemtap.base/at_vma_1.c
new file mode 100644
index 000000000..8c3b7bc46
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_1.c
@@ -0,0 +1,5 @@
+long v = 0xbeefdead;
+
+int main(void) {
+ return 0;
+}
diff --git a/testsuite/systemtap.base/at_vma_1.stp b/testsuite/systemtap.base/at_vma_1.stp
new file mode 100644
index 000000000..857257ad1
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_1.stp
@@ -0,0 +1,9 @@
+function f() {
+ return user_long(@vma(0x$^ADDR_v, "$^PWD/a.out"));
+}
+
+probe process.function("main") {
+ printf("%#x\n", f());
+ printf("%d\n", @vma(0x$^ADDR_v, "$^PWD/a.out") == 0x$^ADDR_v);
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_10.stp b/testsuite/systemtap.base/at_vma_10.stp
new file mode 100644
index 000000000..67a45e7b3
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_10.stp
@@ -0,0 +1,8 @@
+function f() {
+ return user_long(@vma(0x$^ADDR_v, "$^PWD/a.out"));
+}
+
+probe process.function("main") {
+ printf("%#x\n", f());
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_11.stp b/testsuite/systemtap.base/at_vma_11.stp
new file mode 100644
index 000000000..f9e35c5ea
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_11.stp
@@ -0,0 +1,4 @@
+probe process.function("main") {
+ printf("%#x\n", user_long(@vma(0x$^ADDR_v)));
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_12.stp b/testsuite/systemtap.base/at_vma_12.stp
new file mode 100644
index 000000000..eaae7299f
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_12.stp
@@ -0,0 +1,12 @@
+function f() {
+ return user_long(@vma(0x$^ADDR_v, "$^PWD/a.out"));
+}
+
+probe process.function("main") {
+ printf("%#x\n", f());
+ if (!@defined(@var("v"))) {
+ println("no var v found");
+ }
+ printf("%d\n", @vma(0x$^ADDR_v, "$^PWD/a.out") == 0x$^ADDR_v);
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_13.stp b/testsuite/systemtap.base/at_vma_13.stp
new file mode 100644
index 000000000..d49090382
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_13.stp
@@ -0,0 +1,12 @@
+function f() {
+ printf("%d\n", @vma(0x$^ADDR_v, "$^PWD/a.out") == 0x$^ADDR_v);
+ return user_long(@vma(0x$^ADDR_v, "$^PWD/a.out"));
+}
+
+probe process.function("main") {
+ if (!@defined(@var("v"))) {
+ println("no var v found");
+ }
+ printf("%#x\n", f());
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_14.c b/testsuite/systemtap.base/at_vma_14.c
new file mode 100644
index 000000000..eeca645b9
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_14.c
@@ -0,0 +1,5 @@
+long v = 0xdeadbeef;
+
+int main(void) {
+ return 0;
+}
diff --git a/testsuite/systemtap.base/at_vma_14.stp b/testsuite/systemtap.base/at_vma_14.stp
new file mode 100644
index 000000000..c0bbd70eb
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_14.stp
@@ -0,0 +1,3 @@
+probe process.function("main") {
+ @vma(0x$^ADDR_v) = 32;
+}
diff --git a/testsuite/systemtap.base/at_vma_2.stp b/testsuite/systemtap.base/at_vma_2.stp
new file mode 100644
index 000000000..d579700d8
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_2.stp
@@ -0,0 +1,8 @@
+function f() {
+ return user_long(@vma(0x$^ADDR_v));
+}
+
+probe process.function("main") {
+ printf("%#x\n", f());
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_3.stp b/testsuite/systemtap.base/at_vma_3.stp
new file mode 100644
index 000000000..1ae731ad2
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_3.stp
@@ -0,0 +1,5 @@
+probe process.function("main") {
+ printf("%#x\n", user_long(@vma(0x$^ADDR_v, "$^PWD/a.out")));
+ printf("%d\n", @vma(0x$^ADDR_v, "$^PWD/a.out") == 0x$^ADDR_v);
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_4.stp b/testsuite/systemtap.base/at_vma_4.stp
new file mode 100644
index 000000000..01365f11a
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_4.stp
@@ -0,0 +1,5 @@
+probe process.function("main") {
+ printf("%#x\n", user_long(@vma(0x$^ADDR_v)));
+ printf("%d\n", @vma(0x$^ADDR_v, "$^PWD/a.out") == 0x$^ADDR_v);
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_5.stp b/testsuite/systemtap.base/at_vma_5.stp
new file mode 100644
index 000000000..888733eee
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_5.stp
@@ -0,0 +1,9 @@
+function f() {
+ printf("%d\n", @vma(0x$^ADDR_v, "$^PWD/a.out") == 0x$^ADDR_v);
+ return user_long(@vma(0x$^ADDR_v, "$^PWD/a.out"));
+}
+
+probe process.function("main") {
+ printf("%#x\n", f());
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_6.stp b/testsuite/systemtap.base/at_vma_6.stp
new file mode 100644
index 000000000..4a90930a1
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_6.stp
@@ -0,0 +1,5 @@
+probe process.function("main") {
+ printf("%#x\n", user_long(@vma(0x$^ADDR_v, "$^PWD/a.out")));
+ printf("%d\n", @vma(0x$^ADDR_v) == 0x$^ADDR_v);
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_7.stp b/testsuite/systemtap.base/at_vma_7.stp
new file mode 100644
index 000000000..ec8a86142
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_7.stp
@@ -0,0 +1,5 @@
+probe process.function("main") {
+ printf("%#x\n", user_long(@vma(0x$^ADDR_v)));
+ printf("%d\n", @vma(0x$^ADDR_v) == 0x$^ADDR_v);
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_8.stp b/testsuite/systemtap.base/at_vma_8.stp
new file mode 100644
index 000000000..9a39588a6
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_8.stp
@@ -0,0 +1,4 @@
+probe process.function("main") {
+ printf("%p\n", &@vma(0x$^ADDR_v));
+ exit();
+}
diff --git a/testsuite/systemtap.base/at_vma_9.stp b/testsuite/systemtap.base/at_vma_9.stp
new file mode 100644
index 000000000..b9ed14775
--- /dev/null
+++ b/testsuite/systemtap.base/at_vma_9.stp
@@ -0,0 +1,8 @@
+function f() {
+ return user_long(@vma(0x$^ADDR_v, "$^PWD/a.out:$^PWD/a.out"));
+}
+
+probe process.function("main") {
+ printf("%#x\n", f());
+ exit();
+}
diff --git a/translate.cxx b/translate.cxx
index c7e7aa53f..4249a2454 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -237,6 +237,7 @@ struct c_unparser: public unparser, public visitor
void visit_cast_op (cast_op* e);
void visit_autocast_op (autocast_op* e);
void visit_atvar_op (atvar_op* e);
+ void visit_atvma_op (atvma_op* e);
void visit_defined_op (defined_op* e);
void visit_entry_op (entry_op* e);
void visit_perf_op (perf_op* e);
@@ -5315,6 +5316,13 @@ c_unparser::visit_atvar_op (atvar_op* e)
void
+c_unparser::visit_atvma_op (atvma_op* e)
+{
+ throw SEMANTIC_ERROR(_("cannot translate general @vma expression"), e->tok);
+}
+
+
+void
c_unparser::visit_cast_op (cast_op* e)
{
throw SEMANTIC_ERROR(_("cannot translate general @cast expression"), e->tok);
--
2.11.0.295.gd7dffce