diff options
-rw-r--r-- | tapset-procfs.cxx | 65 | ||||
-rw-r--r-- | tapsets.cxx | 36 | ||||
-rw-r--r-- | tapsets.h | 4 |
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); @@ -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); }; |