summaryrefslogtreecommitdiffstats
path: root/translate.cxx
diff options
context:
space:
mode:
authorfche <fche>2005-05-21 01:35:34 +0000
committerfche <fche>2005-05-21 01:35:34 +0000
commit2b066ec1b8801b08052a68282ce34ef9c425ae8f (patch)
treed0b8aadc2521e2fbf1adde2d330bd7a941587087 /translate.cxx
parenta199030a268b007580b57a83b511f97bbb65996f (diff)
downloadsystemtap-steved-2b066ec1b8801b08052a68282ce34ef9c425ae8f.tar.gz
systemtap-steved-2b066ec1b8801b08052a68282ce34ef9c425ae8f.tar.xz
systemtap-steved-2b066ec1b8801b08052a68282ce34ef9c425ae8f.zip
* at long last, a more full-bodied snapshot
2005-05-20 Frank Ch. Eigler <fche@redhat.com> Many changes throughout. Partial sketch of translation output. * elaborate.*: Elaboration pass. * translate.*: Translation pass. * staptree.*: Simplified for visitor concept. * main.cxx: Translator mainline. * *test.cxx: Removed. * testsuite/*: Some new tests, some changed for newer syntax.
Diffstat (limited to 'translate.cxx')
-rw-r--r--translate.cxx1154
1 files changed, 1154 insertions, 0 deletions
diff --git a/translate.cxx b/translate.cxx
new file mode 100644
index 00000000..7e2669f4
--- /dev/null
+++ b/translate.cxx
@@ -0,0 +1,1154 @@
+// semantic analysis pass, beginnings of elaboration
+// Copyright 2005 Red Hat Inc.
+// GPL
+
+#include "config.h"
+#include "staptree.h"
+#include "elaborate.h"
+#include "translate.h"
+#include <iostream>
+
+using namespace std;
+
+
+// ------------------------------------------------------------------------
+// toy provider/unparser pair
+
+
+struct test_derived_probe: public derived_probe
+{
+ test_derived_probe (probe* p);
+ test_derived_probe (probe* p, probe_point* l);
+
+ void emit_registrations (translator_output* o, unsigned i);
+ void emit_deregistrations (translator_output* o, unsigned i);
+ void emit_probe_entries (translator_output* o, unsigned i);
+};
+
+
+
+void
+symresolution_info::derive_probes (probe *p, vector<derived_probe*>& dps)
+{
+ // XXX: there will be real ones coming later
+ for (unsigned i=0; i<p->locations.size(); i++)
+ dps.push_back (new test_derived_probe (p, p->locations[i]));
+}
+
+
+
+// unique name generator
+static unsigned tmpidxgen;
+
+
+struct test_unparser: public unparser, public visitor
+{
+ systemtap_session* session;
+ translator_output* o;
+
+ derived_probe* current_probe;
+ unsigned current_probenum;
+ functiondecl* current_function;
+
+ test_unparser (systemtap_session *ss): session (ss), o (ss->op),
+ current_probe(0), current_function (0) {}
+ ~test_unparser () {}
+
+ void emit_common_header ();
+ void emit_global (vardecl* v);
+ void emit_functionsig (functiondecl* v);
+ void emit_module_init ();
+ void emit_module_exit ();
+ void emit_function (functiondecl* v);
+ void emit_probe (derived_probe* v, unsigned i);
+
+ // XXX: for use by loop/nesting constructs
+ // vector<string> loop_break_labels;
+ // vector<string> loop_continue_labels;
+
+ string c_typename (exp_type e);
+ string c_varname (const string& e);
+
+ void visit_block (block *s);
+ void visit_null_statement (null_statement *s);
+ void visit_expr_statement (expr_statement *s);
+ void visit_if_statement (if_statement* s);
+ void visit_for_loop (for_loop* s);
+ void visit_return_statement (return_statement* s);
+ void visit_delete_statement (delete_statement* s);
+ void visit_literal_string (literal_string* e);
+ void visit_literal_number (literal_number* e);
+ void visit_binary_expression (binary_expression* e);
+ void visit_unary_expression (unary_expression* e);
+ void visit_pre_crement (pre_crement* e);
+ void visit_post_crement (post_crement* e);
+ void visit_logical_or_expr (logical_or_expr* e);
+ void visit_logical_and_expr (logical_and_expr* e);
+ void visit_array_in (array_in* e);
+ void visit_comparison (comparison* e);
+ void visit_concatenation (concatenation* e);
+ void visit_exponentiation (exponentiation* e);
+ void visit_ternary_expression (ternary_expression* e);
+ void visit_assignment (assignment* e);
+ void visit_symbol (symbol* e);
+ void visit_arrayindex (arrayindex* e);
+ void visit_functioncall (functioncall* e);
+};
+
+
+
+// ------------------------------------------------------------------------
+
+
+// Perform inter-script dependency analysis [XXX: later],
+// then provider elaboration and derived probe construction
+// and finally semantic analysis
+// on the reachable set of probes/functions from the user_file
+int
+resolution_pass (systemtap_session& s)
+{
+ int rc = 0;
+
+ for (unsigned i=0; i<s.user_file->probes.size(); i++)
+ {
+ probe* p = s.user_file->probes[i];
+ // XXX: should of course be based on each probe_point
+ derived_probe *dp = new test_derived_probe (p);
+ s.probes.push_back (dp);
+ }
+
+ // XXX: merge functiondecls
+ // XXX: handle library files
+ // XXX: add builtin variables/functions
+ return rc;
+}
+
+
+// ------------------------------------------------------------------------
+
+
+translator_output::translator_output (ostream& f):
+ o2 (0), o (f), tablevel (0)
+{
+}
+
+
+translator_output::translator_output (const string& filename):
+ o2 (new ofstream (filename.c_str ())), o (*o2), tablevel (0)
+{
+}
+
+
+translator_output::~translator_output ()
+{
+ delete o2;
+}
+
+
+ostream&
+translator_output::newline (int indent)
+{
+ assert (indent > 0 || tablevel >= (unsigned)-indent);
+ tablevel += indent;
+ o << endl;
+ for (unsigned i=0; i<tablevel; i++)
+ o << " ";
+ return o;
+}
+
+
+void
+translator_output::indent (int indent)
+{
+ assert (indent > 0 || tablevel >= (unsigned)-indent);
+ tablevel += indent;
+}
+
+
+ostream&
+translator_output::line ()
+{
+ return o;
+}
+
+
+
+// ------------------------------------------------------------------------
+
+
+test_derived_probe::test_derived_probe (probe* p): derived_probe (p)
+{
+}
+
+
+test_derived_probe::test_derived_probe (probe* p, probe_point* l):
+ derived_probe (p, l)
+{
+}
+
+
+void
+test_derived_probe::emit_registrations (translator_output* o, unsigned i)
+{
+ // XXX
+ o->newline() << "rc = 0; /* no registration for probe " << i << " */";
+}
+
+void
+test_derived_probe::emit_deregistrations (translator_output* o, unsigned i)
+{
+ // XXX
+ o->newline() << "rc = 0; /* no deregistration for probe " << i << " */";
+}
+
+
+void
+test_derived_probe::emit_probe_entries (translator_output* o, unsigned j)
+{
+ for (unsigned i=0; i<locations.size(); i++)
+ {
+ probe_point *l = locations[i];
+ o->newline() << "/* location " << i << ": " << *l << " */";
+ o->newline() << "static void enter_" << j << "_" << i << " ()";
+ o->newline() << "{";
+ o->newline(1) << "struct context* c = & contexts [0];";
+ // XXX: assert #0 is free; need locked search instead
+ o->newline() << "if (c->busy) { errorcount ++; return; }";
+ o->newline() << "c->busy ++;";
+ o->newline() << "c->actioncount = 0;";
+ o->newline() << "c->nesting = 0;";
+ // NB: locals are initialized by probe function itself
+ o->newline() << "probe_" << j << " (c);";
+ o->newline() << "c->busy --;";
+ o->newline(-1) << "}" << endl;
+ }
+}
+
+
+// ------------------------------------------------------------------------
+
+
+void
+test_unparser::emit_common_header ()
+{
+ o->newline() << "#include <string.h>";
+ o->newline() << "#define NR_CPU 1";
+ o->newline() << "#define MAXNESTING 30";
+ o->newline() << "#define MAXCONCURRENCY NR_CPU";
+ o->newline() << "#define MAXSTRINGLEN 128";
+ o->newline() << "#define MAXACTION 1000";
+ o->newline();
+ o->newline() << "typedef char string_t[MAXSTRINGLEN];";
+ o->newline() << "typedef struct { int a; } stats_t;";
+ o->newline();
+ o->newline() << "unsigned errorcount;";
+ o->newline() << "struct context {";
+ o->indent(1);
+ o->newline() << "unsigned busy;";
+ o->newline() << "unsigned actioncount;";
+ o->newline() << "unsigned nesting;";
+ o->newline() << "union {";
+ o->indent(1);
+ // XXX: this handles only scalars!
+
+ for (unsigned i=0; i<session->probes.size(); i++)
+ {
+ o->newline() << "struct {";
+ derived_probe* dp = session->probes[i];
+ o->newline(1) << "/* local variables */";
+ for (unsigned j=0; j<dp->locals.size(); j++)
+ {
+ vardecl* v = dp->locals[j];
+ o->newline() << c_typename (v->type) << " "
+ << c_varname (v->name) << ";";
+ }
+ o->newline(-1) << "} probe_" << i << ";";
+ }
+
+ for (unsigned i=0; i<session->functions.size(); i++)
+ {
+ o->newline() << "struct {";
+ functiondecl* fd = session->functions[i];
+ o->newline(1) << "/* local variables */";
+ for (unsigned j=0; j<fd->locals.size(); j++)
+ {
+ vardecl* v = fd->locals[j];
+ o->newline() << c_typename (v->type) << " "
+ << c_varname (v->name) << ";";
+ }
+ o->newline() << "/* formal arguments */";
+ for (unsigned j=0; j<fd->formal_args.size(); j++)
+ {
+ vardecl* v = fd->formal_args[j];
+ o->newline() << c_typename (v->type) << " "
+ << c_varname (v->name) << ";";
+ }
+ if (fd->type == pe_unknown)
+ o->newline() << "/* no return value */";
+ else
+ {
+ o->newline() << "/* return value */";
+ o->newline() << c_typename (fd->type) << " retvalue;";
+ }
+ o->newline(-1) << "} function_" << c_varname (fd->name) << ";";
+ }
+
+ // XXX: must allocate context temporary pool
+
+ o->newline(-1) << "} locals [MAXNESTING];";
+ o->newline(-1) << "} contexts [MAXCONCURRENCY];" << endl;
+}
+
+
+void
+test_unparser::emit_global (vardecl *v)
+{
+ o->newline() << "static "
+ << c_typename (v->type)
+ << " "
+ << "global_" << c_varname (v->name)
+ << ";";
+ /* XXX
+ o->line() << "static DEFINE_RWLOCK("
+ << c_varname (v->name) << "_lock"
+ << ");";
+ */
+}
+
+
+void
+test_unparser::emit_functionsig (functiondecl* v)
+{
+ o->newline() << "static void function_" << v->name
+ << " (struct context *c);";
+}
+
+
+void
+test_unparser::emit_module_init ()
+{
+ o->newline() << "static int STARTUP () {";
+ o->newline(1) << "int anyrc = 0;";
+ o->newline() << "int rc;";
+ // XXX: initialize globals
+ for (unsigned i=0; i<session->probes.size(); i++)
+ {
+ session->probes[i]->emit_registrations (o, i);
+ o->newline() << "anyrc |= rc;";
+ o->newline() << "if (rc) {";
+ o->indent(1);
+ if (i > 0)
+ for (unsigned j=i; j>0; j--)
+ session->probes[j-1]->emit_deregistrations (o, j-1);
+ // XXX: ignore rc
+ o->newline() << "goto out;";
+ o->newline(-1) << "}";
+ }
+ o->newline(-1) << "out:";
+ o->indent(1);
+ o->newline() << "return anyrc; /* if (anyrc) log badness */";
+ o->newline(-1) << "}" << endl;
+}
+
+
+void
+test_unparser::emit_module_exit ()
+{
+ o->newline() << "static int SHUTDOWN () {";
+ o->newline(1) << "int anyrc = 0;";
+ o->newline() << "int rc;";
+ for (unsigned i=0; i<session->probes.size(); i++)
+ {
+ session->probes[i]->emit_deregistrations (o, i);
+ o->newline() << "anyrc |= rc;";
+ }
+ // XXX: uninitialize globals
+ o->newline() << "return anyrc; /* if (anyrc) log badness */";
+ o->newline(-1) << "}" << endl;
+}
+
+
+void
+test_unparser::emit_function (functiondecl* v)
+{
+ o->newline() << "static void function_" << c_varname (v->name)
+ << " (struct context* c) {";
+ o->indent(1);
+ this->current_probe = 0;
+ this->current_probenum = 0;
+ this->current_function = v;
+ v->body->visit (this);
+ this->current_function = 0;
+
+ o->newline(-1) << "out:";
+ o->newline(1) << ";";
+
+ o->newline(-1) << "}" << endl;
+}
+
+
+void
+test_unparser::emit_probe (derived_probe* v, unsigned i)
+{
+ o->newline() << "static void probe_" << i << " (struct context *c) {";
+ o->indent(1);
+
+ o->newline() << "/* initialize locals */";
+ for (unsigned j=0; j<v->locals.size(); j++)
+ {
+ if (v->locals[j]->index_types.size() > 0) // array?
+ throw semantic_error ("not yet implemented", v->tok);
+ else if (v->locals[j]->type == pe_long)
+ o->newline() << "c->locals[c->nesting]"
+ << ".probe_" << i
+ << "." << c_varname (v->locals[j]->name)
+ << " = 0;";
+ else if (v->locals[j]->type == pe_string)
+ o->newline() << "c->locals[c->nesting]"
+ << ".probe_" << i
+ << "." << c_varname (v->locals[j]->name)
+ << "[0] = '\\0';";
+ else
+ throw semantic_error ("unsupported local variable type",
+ v->locals[j]->tok);
+ }
+
+ this->current_function = 0;
+ this->current_probe = v;
+ this->current_probenum = i;
+ v->body->visit (this);
+ this->current_probe = 0;
+ this->current_probenum = 0; // not essential
+
+ o->newline(-1) << "out:";
+ o->newline(1) << ";";
+
+ // XXX: uninitialize locals
+
+ o->newline(-1) << "}" << endl;
+
+ v->emit_probe_entries (o, i);
+}
+
+
+string
+test_unparser::c_typename (exp_type e)
+{
+ switch (e)
+ {
+ case pe_long: return string("long");
+ case pe_string: return string("string_t");
+ case pe_stats: return string("stats_t");
+ case pe_unknown:
+ default:
+ throw semantic_error ("cannot expand unknown type");
+ }
+}
+
+
+string
+test_unparser::c_varname (const string& e)
+{
+ // XXX: safeify, uniquefy, given name
+ return e;
+}
+
+
+void
+test_unparser::visit_block (block *s)
+{
+ const token* t = s->tok;
+ o->newline() << "# " << t->location.line
+ << " \"" << t->location.file << "\" " << endl;
+
+ o->newline() << "{";
+ o->indent (1);
+ for (unsigned i=0; i<s->statements.size(); i++)
+ {
+ try
+ {
+ /* XXX: don't define an individual statement as an action
+ o->newline() << "c->actioncount ++;";
+ o->newline() << "if (c->actioncount > MAXACTION)";
+ o->newline(1) << "errorcount ++;";
+ o->indent(-1);
+ */
+ o->newline() << "if (errorcount)";
+ o->newline(1) << "goto out;" << endl;
+ o->indent(-1);
+
+ s->statements[i]->visit (this);
+ o->newline();
+ }
+ catch (const semantic_error& e)
+ {
+ session->print_error (e);
+ }
+ }
+ o->newline(-1) << "}";
+}
+
+
+void
+test_unparser::visit_null_statement (null_statement *s)
+{
+ const token* t = s->tok;
+ o->newline() << "# " << t->location.line
+ << " \"" << t->location.file << "\" " << endl;
+ o->newline() << "/* null */;";
+}
+
+
+void
+test_unparser::visit_expr_statement (expr_statement *s)
+{
+ const token* t = s->tok;
+ o->newline() << "# " << t->location.line
+ << " \"" << t->location.file << "\" " << endl;
+ o->newline() << "(void) ";
+ s->value->visit (this);
+ o->line() << ";";
+}
+
+
+void
+test_unparser::visit_if_statement (if_statement *s)
+{
+ const token* t = s->tok;
+ o->newline() << "# " << t->location.line
+ << " \"" << t->location.file << "\" " << endl;
+ o->newline() << "if (";
+ o->indent (1);
+ s->condition->visit (this);
+ o->indent (-1);
+ o->line() << ") {";
+ o->indent (1);
+ s->thenblock->visit (this);
+ o->newline(-1) << "}";
+ if (s->elseblock)
+ {
+ o->newline() << "else {";
+ o->indent (1);
+ s->thenblock->visit (this);
+ o->newline(-1) << "}";
+ }
+}
+
+
+void
+test_unparser::visit_for_loop (for_loop *s)
+{
+ const token* t = s->tok;
+ o->newline() << "# " << t->location.line
+ << " \"" << t->location.file << "\" " << endl;
+ throw semantic_error ("not yet implemented", s->tok);
+}
+
+
+void
+test_unparser::visit_return_statement (return_statement* s)
+{
+ const token* t = s->tok;
+ o->newline() << "# " << t->location.line
+ << " \"" << t->location.file << "\" " << endl;
+ if (current_function == 0)
+ throw semantic_error ("cannot return from non-function", s->tok);
+
+ if (s->value->type != current_function->type)
+ throw semantic_error ("return type mismatch", current_function->tok,
+ "vs", s->tok);
+
+ o->newline() << "/* " << *s->tok << " */";
+ if (s->value->type == pe_long)
+ {
+ o->newline() << "c->locals[c->nesting]"
+ << ".function_" << c_varname (current_function->name)
+ << ".retvalue = ";
+ s->value->visit (this);
+ o->line() << ";";
+ }
+ else if (s->value->type == pe_string)
+ {
+ o->newline() << "strncpy (c->locals[c->nesting]"
+ << ".function_" << c_varname (current_function->name)
+ << ".retvalue = ";
+ s->value->visit (this);
+ o->line() << ", MAXSTRINGLEN);";
+ o->line() << ";";
+ }
+ else
+ throw semantic_error ("return type unsupported", s->tok);
+
+ o->newline() << "goto out;";
+}
+
+
+void
+test_unparser::visit_delete_statement (delete_statement* s)
+{
+ const token* t = s->tok;
+ o->newline() << "# " << t->location.line
+ << " \"" << t->location.file << "\" " << endl;
+ throw semantic_error ("not yet implemented", s->tok);
+}
+
+void
+test_unparser::visit_literal_string (literal_string* e)
+{
+ o->line() << '"' << e->value << '"'; // XXX: escape special chars
+}
+
+void
+test_unparser::visit_literal_number (literal_number* e)
+{
+ o->line() << e->value;
+}
+
+void
+test_unparser::visit_binary_expression (binary_expression* e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+void
+test_unparser::visit_unary_expression (unary_expression* e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+void
+test_unparser::visit_pre_crement (pre_crement* e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+void
+test_unparser::visit_post_crement (post_crement* e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+void
+test_unparser::visit_logical_or_expr (logical_or_expr* e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+void
+test_unparser::visit_logical_and_expr (logical_and_expr* e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+void
+test_unparser::visit_array_in (array_in* e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+void
+test_unparser::visit_comparison (comparison* e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+void
+test_unparser::visit_concatenation (concatenation* e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+void
+test_unparser::visit_exponentiation (exponentiation* e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+void
+test_unparser::visit_ternary_expression (ternary_expression* e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+
+
+struct test_unparser_assignment: public throwing_visitor
+{
+ test_unparser* parent;
+ string op;
+ expression* rvalue;
+ test_unparser_assignment (test_unparser* p, const string& o, expression* e):
+ parent (p), op (o), rvalue (e) {}
+
+ // only symbols and arrayindex nodes are lvalues
+ void visit_symbol (symbol *e);
+ void visit_arrayindex (arrayindex *e);
+};
+
+
+void
+test_unparser::visit_assignment (assignment* e)
+{
+ if (e->type != e->left->type)
+ throw semantic_error ("type mismatch", e->tok,
+ "vs", e->left->tok);
+ if (e->right->type != e->left->type)
+ throw semantic_error ("type mismatch", e->right->tok,
+ "vs", e->left->tok);
+
+ if (e->op == "=" || e->op == "<<")
+ {
+ test_unparser_assignment* tav =
+ new test_unparser_assignment (this, e->op, e->right);
+ e->left->visit (tav);
+ }
+ else
+ throw semantic_error ("not yet implemented ", e->tok);
+}
+
+
+void
+test_unparser::visit_symbol (symbol* e)
+{
+ vardecl* r = e->referent;
+
+ if (r->index_types.size() != 0)
+ throw semantic_error ("invalid reference to array", e->tok);
+
+ // XXX: handle special macro symbols
+
+ // maybe the variable is a local
+ if (current_probe)
+ {
+ for (unsigned i=0; i<current_probe->locals.size(); i++)
+ {
+ vardecl* rr = current_probe->locals[i];
+ if (rr == r) // comparison of pointers is sufficient
+ {
+ o->line() << "c->locals[c->nesting]"
+ << ".probe_" << current_probenum
+ << "." << c_varname (r->name);
+ return;
+ }
+ }
+ }
+ else if (current_function)
+ {
+ for (unsigned i=0; i<current_function->locals.size(); i++)
+ {
+ vardecl* rr = current_function->locals[i];
+ if (rr == r) // comparison of pointers is sufficient
+ {
+ o->line() << "c->locals[c->nesting]"
+ << ".function_"
+ << c_varname (current_function->name)
+ << "." << c_varname (r->name);
+ return;
+ }
+ }
+ }
+
+ // it better be a global
+ for (unsigned i=0; i<session->globals.size(); i++)
+ {
+ if (session->globals[i] == r)
+ {
+ // XXX: acquire read lock on global; copy value
+ // into local temporary
+ o->line() << "global_" << c_varname (r->name);
+ return;
+ }
+ }
+
+ throw semantic_error ("unresolved symbol", e->tok);
+}
+
+
+void
+test_unparser_assignment::visit_symbol (symbol *e)
+{
+ vardecl* r = e->referent;
+ translator_output* o = parent->o;
+ functiondecl* current_function = parent->current_function;
+ derived_probe* current_probe = parent->current_probe;
+ unsigned current_probenum = parent->current_probenum;
+ systemtap_session* session = parent->session;
+
+ if (op != "=")
+ throw semantic_error ("not yet implemented", e->tok);
+
+ if (r->index_types.size() != 0)
+ throw semantic_error ("invalid reference to array", e->tok);
+
+ // XXX: handle special macro symbols
+ unsigned tmpidx = ++ tmpidxgen;
+
+ // NB: because assignments are nestable expressions, we have
+ // to emit C constructs that are nestable expressions too.
+ // ... (A = B) ... ==>
+ // ... ({ tmp = B; store(A,tmp); tmp; }) ...
+
+ o->line() << "({ ";
+ o->indent(1);
+
+ // XXX: muse use context temporary pool instead
+ o->newline() << parent->c_typename (e->type)
+ << " tmp" << tmpidx << ";";
+
+ if (e->type == pe_string)
+ o->newline() << "strncpy (";
+ else
+ o->newline();
+ o->line() << "tmp" << tmpidx;
+ o->line() << (e->type == pe_long ? " = " : ", ");
+ rvalue->visit (parent);
+ if (e->type == pe_string)
+ o->line() << ", MAXSTRINGLEN)";
+ o->line() << ";";
+
+ // XXX: strings may be passed safely via a char*, without
+ // a full copy in tmpNNN
+
+ // maybe the variable is a local
+ if (current_probe)
+ {
+ for (unsigned i=0; i<current_probe->locals.size(); i++)
+ {
+ vardecl* rr = current_probe->locals[i];
+ if (rr == r) // comparison of pointers is sufficient
+ {
+ if (e->type == pe_string)
+ o->newline() << "strncpy (";
+ else
+ o->newline();
+ o->line() << "c->locals[c->nesting]"
+ << ".probe_" << current_probenum
+ << "." << parent->c_varname (r->name);
+ o->line() << (e->type == pe_long ? " = " : ", ")
+ << "tmp" << tmpidx;
+ if (e->type == pe_string)
+ o->line() << ", MAXSTRINGLEN)";
+ o->line() << ";";
+ o->newline() << "tmp" << tmpidx << ";";
+ o->newline(-1) << "})";
+ return;
+ }
+ }
+ }
+ else if (current_function)
+ {
+ for (unsigned i=0; i<current_function->locals.size(); i++)
+ {
+ vardecl* rr = current_function->locals[i];
+ if (rr == r) // comparison of pointers is sufficient
+ {
+ if (e->type == pe_string)
+ o->newline() << "strncpy (";
+ else
+ o->newline();
+ o->line() << "c->locals[c->nesting]"
+ << ".function_"
+ << parent->c_varname (current_function->name)
+ << "." << parent->c_varname (r->name);
+ o->line() << (e->type == pe_long ? " = " : ", ")
+ << "tmp" << tmpidx;
+ if (e->type == pe_string)
+ o->line() << ", MAXSTRINGLEN)";
+ o->line() << ";";
+ o->newline() << "tmp" << tmpidx << ";";
+ o->newline(-1) << "})";
+ return;
+ }
+ }
+ }
+
+ // it better be a global
+ for (unsigned i=0; i<session->globals.size(); i++)
+ {
+ if (session->globals[i] == r)
+ {
+ // XXX: acquire write lock on global
+ if (e->type == pe_string)
+ o->newline() << "strncpy (";
+ else
+ o->newline();
+ o->line() << "global_" << parent->c_varname (r->name);
+ o->line() << (e->type == pe_long ? " = " : ", ")
+ << "tmp" << tmpidx;
+ if (e->type == pe_string)
+ o->line() << ", MAXSTRINGLEN)";
+ o->line() << ";";
+ o->newline() << "tmp" << tmpidx << ";";
+ o->newline(-1) << "})";
+ return;
+ }
+ }
+
+ throw semantic_error ("unresolved symbol", e->tok);
+}
+
+
+void
+test_unparser::visit_arrayindex (arrayindex* e)
+{
+ vardecl* r = e->referent;
+
+ if (r->index_types.size() == 0 ||
+ r->index_types.size() != e->indexes.size())
+ throw semantic_error ("invalid array reference", e->tok);
+
+ o->line() << "({";
+ o->indent(1);
+
+ o->newline() << "c->actioncount ++;";
+ o->newline() << "if (c->actioncount > MAXACTION)";
+ o->newline(1) << "errorcount ++;";
+ o->indent(-1);
+
+ o->newline() << "if (errorcount)";
+ o->newline(1) << "goto out;";
+ o->indent(-1);
+
+ // NB: because these expressions are nestable, emit this construct
+ // thusly:
+ // ({ tmp0=(idx0); ... tmpN=(idxN);
+ // fetch (array,idx0...N, &tmpresult);
+ // tmpresult; })
+ //
+ // we store all indices in temporary variables to avoid nasty
+ // reentrancy issues that pop up with nested expressions:
+ // e.g. a[a[c]=5] could deadlock
+
+ vector<unsigned> idxtmps;
+ for (unsigned i=0; i<r->index_types.size(); i++)
+ {
+ if (r->index_types[i] != e->indexes[i]->type)
+ throw semantic_error ("array index type mismatch", e->indexes[i]->tok);
+
+ unsigned tmpidx = ++ tmpidxgen;
+ idxtmps.push_back (tmpidx);
+ // XXX: muse use context temporary pool instead
+ o->newline() << c_typename (r->index_types[i]) << " tmp" << tmpidx << ";";
+ if (e->indexes[i]->type == pe_string)
+ o->newline() << "strncpy (";
+ else
+ o->newline();
+ o->line() << "tmp" << tmpidx;
+ o->line() << (e->indexes[i]->type == pe_long ? " = " : ", ");
+ e->indexes[i]->visit (this);
+ if (e->indexes[i]->type == pe_string)
+ o->line() << ", MAXSTRINGLEN)";
+ o->line() << ";";
+ }
+
+ o->newline() << "if (errorcount)";
+ o->newline(1) << "goto out;";
+ o->indent(-1);
+
+ o->newline() << c_typename (r->type) << " result;";
+
+#if 0
+ // maybe the variable is a local
+ if (current_probe)
+ {
+ for (unsigned i=0; i<current_probe->locals.size(); i++)
+ {
+ vardecl* rr = current_probe->locals[i];
+ if (rr == r) // comparison of pointers is sufficient
+ {
+ o->line() << "c->locals[c->nesting]"
+ << ".probe_" << current_probenum
+ << "." << c_varname (r->name);
+ return;
+ }
+ }
+ }
+ else if (current_function)
+ {
+ for (unsigned i=0; i<current_function->locals.size(); i++)
+ {
+ vardecl* rr = current_function->locals[i];
+ if (rr == r) // comparison of pointers is sufficient
+ {
+ o->line() << "c->locals[c->nesting]"
+ << ".function_"
+ << c_varname (current_function->name)
+ << "." << c_varname (r->name);
+ return;
+ }
+ }
+ }
+
+ // it better be a global
+ for (unsigned i=0; i<session->globals.size(); i++)
+ {
+ if (session->globals[i] == r)
+ {
+ // XXX: acquire read lock on global; copy value
+ // into local temporary
+ o->line() << "global_" << c_varname (r->name);
+ return;
+ }
+ }
+
+ throw semantic_error ("unresolved symbol", e->tok);
+#endif
+
+
+ o->newline() << "result;";
+ o->newline(-1) << "})";
+}
+
+
+void
+test_unparser_assignment::visit_arrayindex (arrayindex *e)
+{
+ throw semantic_error ("not yet implemented", e->tok);
+}
+
+
+void
+test_unparser::visit_functioncall (functioncall* e)
+{
+ functiondecl* r = e->referent;
+
+ if (r->formal_args.size() != e->args.size())
+ throw semantic_error ("invalid length argument list", e->tok);
+
+ o->line() << "({";
+ o->indent(1);
+
+ // NB: we store all actual arguments in temporary variables,
+ // to avoid colliding sharing of context variables with
+ // nested function calls: f(f(f(1)))
+
+ o->newline() << "/* compute actual arguments */";
+ for (unsigned i=0; i<e->args.size(); i++)
+ {
+ if (r->formal_args[i]->type != e->args[i]->type)
+ throw semantic_error ("function argument type mismatch",
+ e->args[i]->tok, "vs", r->formal_args[i]->tok);
+
+ // XXX: muse use context temporary pool instead
+ o->newline() << c_typename (r->formal_args[i]->type)
+ << " tmp_" << r->formal_args[i]->name << ";";
+ if (e->args[i]->type == pe_string)
+ o->newline() << "strncpy (";
+ else
+ o->newline();
+ o->line() << "tmp_" << c_varname (r->formal_args[i]->name);
+ o->line() << (e->args[i]->type == pe_long ? " = " : ", ");
+ e->args[i]->visit (this);
+ if (e->args[i]->type == pe_string)
+ o->line() << ", MAXSTRINGLEN)";
+ o->line() << ";";
+ }
+
+ o->newline() << "if (c->nesting+2 >= MAXNESTING)";
+ o->newline(1) << "errorcount ++;";
+ o->newline(-1) << "c->actioncount ++;";
+ o->newline() << "if (c->actioncount > MAXACTION)";
+ o->newline(1) << "errorcount ++;";
+ o->newline(-1) << "if (errorcount)";
+ o->newline(1) << "goto out;";
+ o->indent(-1);
+
+ o->newline() << "/* initialize locals */";
+ for (unsigned i=0; i<r->locals.size(); i++)
+ {
+ if (r->locals[i]->index_types.size() > 0) // array?
+ throw semantic_error ("not yet implemented", r->tok);
+ else if (r->locals[i]->type == pe_long)
+ o->newline() << "c->locals[c->nesting+1]"
+ << ".function_" << c_varname (r->name)
+ << "." << c_varname (r->locals[i]->name)
+ << " = 0;";
+ else if (r->locals[i]->type == pe_string)
+ o->newline() << "c->locals[c->nesting+1]"
+ << ".function_" << c_varname (r->name)
+ << "." << c_varname (r->locals[i]->name)
+ << "[0] = '\\0';";
+ else
+ throw semantic_error ("unsupported local variable type",
+ r->locals[i]->tok);
+ }
+
+ o->newline() << "if (errorcount)";
+ o->newline(1) << "goto out;";
+ o->indent(-1);
+
+ o->newline() << "/* copy in stored actual arguments */";
+ for (unsigned i=0; i<e->args.size(); i++)
+ {
+ if (r->formal_args[i]->type != e->args[i]->type)
+ throw semantic_error ("function argument type mismatch",
+ e->args[i]->tok, "vs", r->formal_args[i]->tok);
+
+ if (e->args[i]->type == pe_string)
+ o->newline() << "strncpy (";
+ else
+ o->newline();
+ o->line() << "c->locals[c->nesting+1]"
+ << ".function_" << c_varname (r->name)
+ << "." << c_varname (r->formal_args[i]->name);
+ o->line() << (e->args[i]->type == pe_long ? " = " : ", ");
+ o->line() << "tmp_" << c_varname (r->formal_args[i]->name);
+ if (e->args[i]->type == pe_string)
+ o->line() << ", MAXSTRINGLEN)";
+ o->line() << ";";
+ }
+
+ // call function
+ o->newline() << "c->nesting ++;";
+ o->newline() << "function_" << c_varname (r->name) << " (c);";
+ o->newline() << "c->nesting --;";
+
+ // XXX: clean up any locals that need it (arrays)
+
+ // return result from retvalue slot
+ o->newline() << "c->locals[c->nesting+1]"
+ << ".function_" << c_varname (r->name)
+ << ".retvalue;";
+
+ o->newline(-1) << "})";
+}
+
+
+
+int
+translate_pass (systemtap_session& s)
+{
+ int rc = 0;
+
+ s.up = new test_unparser (& s);
+
+ try
+ {
+ s.op->newline() << "/* common header */";
+ s.up->emit_common_header ();
+ s.op->newline() << "/* globals */";
+ for (unsigned i=0; i<s.globals.size(); i++)
+ s.up->emit_global (s.globals[i]);
+ s.op->newline() << "/* function signatures */";
+ for (unsigned i=0; i<s.functions.size(); i++)
+ s.up->emit_functionsig (s.functions[i]);
+ s.op->newline() << "/* functions */";
+ for (unsigned i=0; i<s.functions.size(); i++)
+ s.up->emit_function (s.functions[i]);
+ s.op->newline() << "/* probes */";
+ for (unsigned i=0; i<s.probes.size(); i++)
+ s.up->emit_probe (s.probes[i], i);
+ s.op->newline() << "/* module init */";
+ s.up->emit_module_init ();
+ s.op->newline() << "/* module exit */";
+ s.up->emit_module_exit ();
+ s.op->newline();
+ }
+ catch (const semantic_error& e)
+ {
+ s.print_error (e);
+ }
+
+ delete s.up;
+ return rc + s.num_errors;
+}