// 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 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& dps) { // XXX: there will be real ones coming later for (unsigned i=0; ilocations.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 loop_break_labels; // vector 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; iprobes.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 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; inewline() << "/* 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 "; 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; iprobes.size(); i++) { o->newline() << "struct {"; derived_probe* dp = session->probes[i]; o->newline(1) << "/* local variables */"; for (unsigned j=0; jlocals.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; ifunctions.size(); i++) { o->newline() << "struct {"; functiondecl* fd = session->functions[i]; o->newline(1) << "/* local variables */"; for (unsigned j=0; jlocals.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; jformal_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; iprobes.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; iprobes.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; jlocals.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; istatements.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; ilocals.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; ilocals.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; iglobals.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; ilocals.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; ilocals.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; iglobals.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 idxtmps; for (unsigned i=0; iindex_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; ilocals.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; ilocals.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; iglobals.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; iargs.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; ilocals.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; iargs.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; iemit_global (s.globals[i]); s.op->newline() << "/* function signatures */"; for (unsigned i=0; iemit_functionsig (s.functions[i]); s.op->newline() << "/* functions */"; for (unsigned i=0; iemit_function (s.functions[i]); s.op->newline() << "/* probes */"; for (unsigned i=0; iemit_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; }