summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tapset-procfs.cxx65
-rw-r--r--tapsets.cxx36
-rw-r--r--tapsets.h4
3 files changed, 84 insertions, 21 deletions
diff --git a/tapset-procfs.cxx b/tapset-procfs.cxx
index c4eb54f3..d05ab52c 100644
--- a/tapset-procfs.cxx
+++ b/tapset-procfs.cxx
@@ -74,9 +74,7 @@ public:
struct procfs_var_expanding_visitor: public var_expanding_visitor
{
procfs_var_expanding_visitor(systemtap_session& s, const string& pn,
- string path, bool write_probe):
- sess (s), probe_name (pn), path (path), write_probe (write_probe),
- target_symbol_seen (false) {}
+ string path, bool write_probe);
systemtap_session& sess;
string probe_name;
@@ -342,6 +340,18 @@ procfs_derived_probe_group::emit_module_exit (systemtap_session& s)
}
+procfs_var_expanding_visitor::procfs_var_expanding_visitor (systemtap_session& s,
+ const string& pn,
+ string path,
+ bool write_probe):
+ sess (s), probe_name (pn), path (path), write_probe (write_probe),
+ target_symbol_seen (false)
+{
+ // procfs probes can also handle '.='.
+ valid_ops.insert (".=");
+}
+
+
void
procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e)
{
@@ -371,21 +381,48 @@ procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e)
embeddedcode *ec = new embeddedcode;
ec->tok = e->tok;
- string fname = (string(lvalue ? "_procfs_value_set" : "_procfs_value_get"));
+ string fname;
string locvalue = "CONTEXT->data";
if (! lvalue)
- ec->code = string(" struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue + string("); /* pure */\n")
+ {
+ if (*op == "=")
+ {
+ fname = "_procfs_value_get";
+ ec->code = string(" struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue + string("); /* pure */\n")
- + string(" _stp_copy_from_user(THIS->__retvalue, data->buffer, data->count);\n")
- + string(" THIS->__retvalue[data->count] = '\\0';\n");
- else
- ec->code = string("int bytes = 0;\n")
- + string(" struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue + string(");\n")
- + string(" bytes = strnlen(THIS->value, MAXSTRINGLEN - 1);\n")
- + string(" memcpy((void *)data->buffer, THIS->value, bytes);\n")
- + string(" data->buffer[bytes] = '\\0';\n")
- + string(" data->count = bytes;\n");
+ + string(" _stp_copy_from_user(THIS->__retvalue, data->buffer, data->count);\n")
+ + string(" THIS->__retvalue[data->count] = '\\0';\n");
+ }
+ else
+ {
+ throw semantic_error ("Operator-assign expressions on procfs write"
+ " target variables not implemented", e->tok);
+ }
+ }
+ else // lvalue
+ {
+ if (*op == "=")
+ {
+ fname = "_procfs_value_set";
+ ec->code = string("struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue + string(");\n")
+ + string(" strlcpy(data->buffer, THIS->value, MAXSTRINGLEN);\n")
+ + string(" data->count = strlen(data->buffer);\n");
+ }
+ else if (*op == ".=")
+ {
+ fname = "_procfs_value_append";
+ ec->code = string("struct _stp_procfs_data *data = (struct _stp_procfs_data *)(") + locvalue + string(");\n")
+ + string(" strlcat(data->buffer, THIS->value, MAXSTRINGLEN);\n")
+ + string(" data->count = strlen(data->buffer);\n");
+ }
+ else
+ {
+ throw semantic_error ("Only the following assign operators are"
+ " implemented on procfs read target variables:"
+ " '=', '.='", e->tok);
+ }
+ }
fdecl->name = fname;
fdecl->body = ec;
diff --git a/tapsets.cxx b/tapsets.cxx
index 9184e288..62191c85 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -1859,6 +1859,19 @@ private:
unsigned var_expanding_visitor::tick = 0;
+
+var_expanding_visitor::var_expanding_visitor ()
+{
+ // FIXME: for the time being, by default we only support plain '$foo
+ // = bar', not '+=' or any other op= variant. This is fixable, but a
+ // bit ugly.
+ //
+ // If derived classes desire to add additional operator support, add
+ // new operators to this list in the derived class constructor.
+ valid_ops.insert ("=");
+}
+
+
void
var_expanding_visitor::visit_assignment (assignment* e)
{
@@ -1877,6 +1890,9 @@ var_expanding_visitor::visit_assignment (assignment* e)
functioncall *fcall = NULL;
expression *new_left, *new_right;
+ // Let visit_target_symbol know what operator it should handle.
+ op = &e->op;
+
target_symbol_setter_functioncalls.push (&fcall);
new_left = require (e->left);
target_symbol_setter_functioncalls.pop ();
@@ -1890,12 +1906,20 @@ var_expanding_visitor::visit_assignment (assignment* e)
// right child spliced in as sole argument -- in place of
// ourselves, in the var expansion we're in the middle of making.
- // FIXME: for the time being, we only support plan $foo = bar,
- // not += or any other op= variant. This is fixable, but a bit
- // ugly.
- if (e->op != "=")
- throw semantic_error ("Operator-assign expressions on target "
- "variables not implemented", e->tok);
+ if (valid_ops.find (e->op) == valid_ops.end ())
+ {
+ // Build up a list of supported operators.
+ string ops;
+ std::set<string>::iterator i;
+ for (i = valid_ops.begin(); i != valid_ops.end(); i++)
+ ops += " " + *i + ",";
+ ops.resize(ops.size() - 1); // chop off the last ','
+
+ // Throw the error.
+ throw semantic_error ("Only the following assign operators are"
+ " implemented on target variables:" + ops,
+ e->tok);
+ }
assert (new_left == fcall);
fcall->args.push_back (new_right);
diff --git a/tapsets.h b/tapsets.h
index 115f2ccf..d415ef42 100644
--- a/tapsets.h
+++ b/tapsets.h
@@ -49,8 +49,10 @@ struct var_expanding_visitor: public update_visitor
{
static unsigned tick;
std::stack<functioncall**> target_symbol_setter_functioncalls;
+ std::set<std::string> valid_ops;
+ std::string *op;
- var_expanding_visitor() {}
+ var_expanding_visitor ();
void visit_assignment (assignment* e);
};