diff options
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | elaborate.cxx | 1 | ||||
-rw-r--r-- | parse.cxx | 1 | ||||
-rwxr-xr-x | runtest.sh | 7 | ||||
-rw-r--r-- | runtime/ChangeLog | 4 | ||||
-rw-r--r-- | runtime/arith.c | 22 | ||||
-rw-r--r-- | tapset/builtin_logging.stp | 5 | ||||
-rw-r--r-- | tapsets.cxx | 47 | ||||
-rw-r--r-- | translate.cxx | 77 |
9 files changed, 111 insertions, 66 deletions
@@ -1,3 +1,16 @@ +2005-08-21 Frank Ch. Eigler <fche@redhat.com> + + PR systemtap/1195, systemtap/1193 + * elaborate.cxx (alias_expansion_builder): Set new block token. + * parse.cxx (parse_symbol): Set new target_symbol token. + * runtest.sh: Store more pertinent failure data. + * tapsets.cxx (emit_probe_entries): Rewrite error-handling path. + * translate.cxx (emit_common_header): Goodbye errorcount, hello + last_error & last_stmt. + (c_unparser::visit_statement): New "header" for all other stmts. + (c_assignop, visit_binary_expression): Adapt to last_error. + * tapset/builtin_logging.stp: Adapt to last_error. + 2005-08-19 Frank Ch. Eigler <fche@elastic.org> PR systemtap/1213 diff --git a/elaborate.cxx b/elaborate.cxx index 53cab841..232f91a5 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -290,6 +290,7 @@ alias_expansion_builder // the token location of the use, n->tok = use->tok; + n->body->tok = use->tok; // and statements representing the concatenation of the alias' // body with the use's. @@ -1621,6 +1621,7 @@ parser::parse_symbol () { // target_symbol time target_symbol *tsym = new target_symbol; + tsym->tok = t; tsym->base_name = name; while (true) { @@ -18,16 +18,19 @@ export SYSTEMTAP_RUNTIME dn=`dirname $1` logfile=testsuite/`basename $dn`-`basename $1` +env | grep SYSTEMTAP > $logfile.cmd +echo "$@" >> $logfile.cmd eval $@ >$logfile.out 2>$logfile.err rc=$? +echo "rc=$rc" > $logfile.rc if expr $1 : '.*ok/.*' >/dev/null; then if [ $rc -eq 0 ]; then - rm -f $logfile.out $logfile.err + rm -f $logfile.* fi else if [ $rc -eq 1 ]; then - rm -f $logfile.out $logfile.err + rm -f $logfile.* fi fi diff --git a/runtime/ChangeLog b/runtime/ChangeLog index f4f791dd..b9c92140 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,7 @@ +2005-08-21 Frank Ch. Eigler <fche@redhat.com> + + * arith.c (*): Adapt to last_error context variable. + 2005-08-19 Frank Ch. Eigler <fche@elastic.org> * arith.c (_stp_random_pm): New function. diff --git a/runtime/arith.c b/runtime/arith.c index 0200afa6..b1759e2a 100644 --- a/runtime/arith.c +++ b/runtime/arith.c @@ -7,14 +7,14 @@ struct context; -void _stp_divmod64 (unsigned *errorcount, int64_t x, int64_t y, +void _stp_divmod64 (const char **error, int64_t x, int64_t y, int64_t *quo, int64_t *rem); /** Divide x by y. In case of overflow or division-by-zero, - * increment context errorcount, and return any old value. + * set context error string, and return any old value. */ -inline int64_t _stp_div64 (unsigned *errorcount, int64_t x, int64_t y) +inline int64_t _stp_div64 (const char **error, int64_t x, int64_t y) { if (likely ((x >= LONG_MIN && x <= LONG_MAX) && (y >= LONG_MIN && y <= LONG_MAX))) @@ -24,7 +24,7 @@ inline int64_t _stp_div64 (unsigned *errorcount, int64_t x, int64_t y) // check for division-by-zero and overflow if (unlikely (yy == 0 || (xx == LONG_MIN && yy == -1))) { - (*errorcount) ++; + *error = "divisor out of range"; return 0; } return xx / yy; @@ -32,16 +32,16 @@ inline int64_t _stp_div64 (unsigned *errorcount, int64_t x, int64_t y) else { int64_t quo = 0; - _stp_divmod64 (errorcount, x, y, &quo, NULL); + _stp_divmod64 (error, x, y, &quo, NULL); return quo; } } /** Modulo x by y. In case of overflow or division-by-zero, - * increment context errorcount, and return any old value. + * set context error string, and return any old value. */ -inline int64_t _stp_mod64 (unsigned *errorcount, int64_t x, int64_t y) +inline int64_t _stp_mod64 (const char **error, int64_t x, int64_t y) { if (likely ((x >= LONG_MIN && x <= LONG_MAX) && (y >= LONG_MIN && y <= LONG_MAX))) @@ -51,7 +51,7 @@ inline int64_t _stp_mod64 (unsigned *errorcount, int64_t x, int64_t y) // check for division-by-zero and overflow if (unlikely (yy == 0 || (xx == LONG_MIN && yy == -1))) { - (*errorcount) ++; + *error = "divisor out of range"; return 0; } return xx % yy; @@ -59,18 +59,18 @@ inline int64_t _stp_mod64 (unsigned *errorcount, int64_t x, int64_t y) else { int64_t rem = 0; - _stp_divmod64 (errorcount, x, y, NULL, &rem); + _stp_divmod64 (error, x, y, NULL, &rem); return rem; } } /** Perform general long division/modulus. */ -void _stp_divmod64 (unsigned *errorcount, int64_t x, int64_t y, +void _stp_divmod64 (const char **error, int64_t x, int64_t y, int64_t *quo, int64_t *rem) { // XXX: wimp out for now - (*errorcount) ++; + *error = "general division unsupported"; if (quo) *quo = 0; if (rem) *rem = 0; } diff --git a/tapset/builtin_logging.stp b/tapset/builtin_logging.stp index 11b00cab..bf01a0fc 100644 --- a/tapset/builtin_logging.stp +++ b/tapset/builtin_logging.stp @@ -25,12 +25,13 @@ function warn (msg) { } function exit () %{ - CONTEXT->errorcount ++; /* kill current probe */ + /* not a NULL pointer, but don't cause _stp_error */ + CONTEXT->last_error = ""; _stp_exit (); %} function _error (msg) %{ - CONTEXT->errorcount ++; /* kill current probe */ + CONTEXT->last_error = "called error()"; /* kill current probe */ _stp_error ("%s", THIS->msg); /* implies _stp_exit */ %} diff --git a/tapsets.cxx b/tapsets.cxx index 45a77a8a..43f18c66 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -118,21 +118,17 @@ be_derived_probe::emit_probe_entries (translator_output* o, unsigned j) o->newline() << "c->busy ++;"; o->newline() << "mb ();"; // for smp - o->newline() << "c->errorcount = 0;"; - o->newline() << "c->actioncount = 0;"; + o->newline() << "c->last_error = 0;"; o->newline() << "c->nesting = 0;"; o->newline() << "c->regs = 0;"; + o->newline() << "c->actioncount = 0;"; // NB: locals are initialized by probe function itself o->newline() << "probe_" << j << " (c);"; - // see translate.cxx: visit_functioncall and elsewhere to see all the - // possible context indications that a probe exited prematurely - o->newline() << "if (c->errorcount || c->actioncount > MAXACTION" - << " || c->nesting+2 >= MAXNESTING) {"; - o->newline(1) << "printk (KERN_ERR \"probe execution failure (e%d,n%d,a%d)\","; - o->newline(1) << "c->errorcount, c->nesting, c->actioncount);"; - o->newline(-1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; + o->newline() << "if (c->last_error) {"; + o->newline(1) << "if (c->last_error[0]) _stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; + o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline(-1) << "}"; o->newline() << "c->busy --;"; @@ -860,7 +856,7 @@ dwflpp if (deref) ; fprintf(memstream, "deref_fault:\n" - " c->errorcount++; \n" + " c->last_error = \"pointer dereference fault\";\n" " goto out;\n"); fclose (memstream); @@ -1460,6 +1456,7 @@ var_expanding_copy_visitor::visit_target_symbol (target_symbol *e) // synthesize a function functiondecl *fdecl = new functiondecl; embeddedcode *ec = new embeddedcode; + ec->tok = e->tok; ec->code = q.dw.literal_stmt_for_local(addr, e->base_name.substr(1), e->components); @@ -1709,20 +1706,17 @@ dwarf_derived_probe::emit_probe_entries (translator_output* o, unsigned probenum o->newline() << "c->busy ++;"; o->newline() << "mb ();"; // for smp - o->newline() << "c->errorcount = 0;"; - o->newline() << "c->actioncount = 0;"; + o->newline() << "c->last_error = 0;"; o->newline() << "c->nesting = 0;"; o->newline() << "c->regs = regs;"; + o->newline() << "c->actioncount = 0;"; + // NB: locals are initialized by probe function itself o->newline() << "probe_" << probenum << " (c);"; - // see translate.cxx: visit_functioncall and elsewhere to see all the - // possible context indications that a probe exited prematurely - o->newline() << "if (c->errorcount || c->actioncount > MAXACTION" - << " || c->nesting+2 >= MAXNESTING) {"; - o->newline(1) << "printk (KERN_ERR \"probe execution failure (e%d,n%d,a%d)\","; - o->newline(1) << "c->errorcount, c->nesting, c->actioncount);"; - o->newline(-1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; + o->newline() << "if (c->last_error) {"; + o->newline(1) << "if (c->last_error[0]) _stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; + o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline(-1) << "}"; o->newline() << "c->busy --;"; @@ -1876,26 +1870,21 @@ timer_derived_probe::emit_probe_entries (translator_output* o, unsigned j) o->newline() << "c->busy ++;"; o->newline() << "mb ();"; // for smp - o->newline() << "c->errorcount = 0;"; - o->newline() << "c->actioncount = 0;"; + o->newline() << "c->last_error = 0;"; o->newline() << "c->nesting = 0;"; - o->newline() << "if (! in_interrupt())"; o->newline(1) << "c->regs = 0;"; o->newline(-1) << "else"; o->newline(1) << "c->regs = task_pt_regs (current);"; o->indent(-1); + o->newline() << "c->actioncount = 0;"; // NB: locals are initialized by probe function itself o->newline() << "probe_" << j << " (c);"; - // see translate.cxx: visit_functioncall and elsewhere to see all the - // possible context indications that a probe exited prematurely - o->newline() << "if (c->errorcount || c->actioncount > MAXACTION" - << " || c->nesting+2 >= MAXNESTING) {"; - o->newline(1) << "printk (KERN_ERR \"probe execution failure (e%d,n%d,a%d)\","; - o->newline(1) << "c->errorcount, c->nesting, c->actioncount);"; - o->newline(-1) << "atomic_set (& session_state, STAP_SESSION_ERROR);"; + o->newline() << "if (c->last_error) {"; + o->newline(1) << "if (c->last_error[0]) _stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; + o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline(-1) << "}"; o->newline() << "c->busy --;"; diff --git a/translate.cxx b/translate.cxx index 3a8d0bec..9c1167fd 100644 --- a/translate.cxx +++ b/translate.cxx @@ -95,6 +95,8 @@ struct c_unparser: public unparser, public visitor set< exp_type > & value_types, set< vector<exp_type> > & index_types); + void visit_statement (statement* s, unsigned actions); + void visit_block (block* s); void visit_embeddedcode (embeddedcode* s); void visit_null_statement (null_statement* s); @@ -530,8 +532,9 @@ c_unparser::emit_common_header () o->newline() << "struct context {"; o->newline(1) << "unsigned busy;"; o->newline() << "unsigned actioncount;"; - o->newline() << "unsigned errorcount;"; o->newline() << "unsigned nesting;"; + o->newline() << "const char *last_error;"; + o->newline() << "const char *last_stmt;"; o->newline() << "struct pt_regs *regs;"; o->newline() << "union {"; o->indent(1); @@ -767,9 +770,7 @@ c_unparser::emit_function (functiondecl* v) o->newline() << retvalue.init(); } - o->newline(1) << "{"; // in case body is embeddedcode with decls v->body->visit (this); - o->newline(-1) << "}"; this->current_function = 0; @@ -1110,10 +1111,10 @@ c_unparser_assignment::c_assignop(tmpvar & res, else { if (macop == "/") - o->newline() << res << " = _stp_div64 (&c->errorcount, " + o->newline() << res << " = _stp_div64 (&c->last_error, " << lval << ", " << rval << ");"; else if (macop == "%") - o->newline() << res << " = _stp_mod64 (&c->errorcount, " + o->newline() << res << " = _stp_mod64 (&c->last_error, " << lval << ", " << rval << ");"; else o->newline() << res << " = " << lval << " " << macop << " " << rval << ";"; @@ -1246,20 +1247,37 @@ c_unparser::getiter(foreach_loop *f) } + +// An artificial common "header" for each statement. This is where +// activity counts limits and error state early exits are enforced. +void +c_unparser::visit_statement (statement *s, unsigned actions) +{ + o->newline() << "if (unlikely (c->last_error)) goto out;"; + assert (s->tok); + o->newline() << "c->last_stmt = \"" << *s->tok << "\";"; + if (actions > 0) + { + o->newline() << "c->actioncount += " << actions << ";"; + o->newline() << "if (unlikely (c->actioncount > MAXACTION)) {"; + o->newline(1) << "c->last_error = \"MAXACTION exceeded\";"; + o->newline() << "goto out;"; + o->newline(-1) << "}"; + } +} + + void c_unparser::visit_block (block *s) { o->newline() << "{"; o->indent (1); - o->newline() << "c->actioncount += " << s->statements.size() << ";"; - o->newline() << "if (unlikely (c->actioncount > MAXACTION)) goto out;"; + visit_statement (s, 0); for (unsigned i=0; i<s->statements.size(); i++) { try { - // XXX: it's probably not necessary to check this so frequently - o->newline() << "if (unlikely (c->errorcount)) goto out;"; s->statements[i]->visit (this); o->newline(); } @@ -1275,13 +1293,17 @@ c_unparser::visit_block (block *s) void c_unparser::visit_embeddedcode (embeddedcode *s) { - o->newline() << s->code; + visit_statement (s, 1); + o->newline() << "{"; + o->newline(1) << s->code; + o->newline(-1) << "}"; } void c_unparser::visit_null_statement (null_statement *s) { + visit_statement (s, 0); o->newline() << "/* null */;"; } @@ -1289,6 +1311,7 @@ c_unparser::visit_null_statement (null_statement *s) void c_unparser::visit_expr_statement (expr_statement *s) { + visit_statement (s, 1); o->newline() << "(void) "; s->value->visit (this); o->line() << ";"; @@ -1298,6 +1321,7 @@ c_unparser::visit_expr_statement (expr_statement *s) void c_unparser::visit_if_statement (if_statement *s) { + visit_statement (s, 1); o->newline() << "if ("; o->indent (1); s->condition->visit (this); @@ -1319,6 +1343,8 @@ c_unparser::visit_if_statement (if_statement *s) void c_unparser::visit_for_loop (for_loop *s) { + visit_statement (s, 1); + s->init->visit (this); string ctr = stringify (label_counter++); string contlabel = "continue_" + ctr; @@ -1326,9 +1352,6 @@ c_unparser::visit_for_loop (for_loop *s) o->newline() << contlabel << ":"; - o->newline() << "c->actioncount ++;"; - o->newline() << "if (unlikely (c->actioncount > MAXACTION)) goto out;"; - o->newline() << "if (! ("; if (s->cond->type != pe_long) throw semantic_error ("expected numeric type", s->cond->tok); @@ -1359,6 +1382,8 @@ c_tmpcounter::visit_foreach_loop (foreach_loop *s) void c_unparser::visit_foreach_loop (foreach_loop *s) { + visit_statement (s, 1); + mapvar mv = getmap (s->base_referent, s->tok); itervar iv = getiter (s); vector<var> keys; @@ -1378,7 +1403,7 @@ c_unparser::visit_foreach_loop (foreach_loop *s) var v = getvar (s->indexes[i]->referent); c_assign (v, iv.get_key (v.type(), i), s->tok); } - + s->block->visit (this); o->indent (-1); @@ -1389,6 +1414,8 @@ c_unparser::visit_foreach_loop (foreach_loop *s) void c_unparser::visit_return_statement (return_statement* s) { + visit_statement (s, 1); + if (current_function == 0) throw semantic_error ("cannot 'return' from probe", s->tok); @@ -1404,6 +1431,8 @@ c_unparser::visit_return_statement (return_statement* s) void c_unparser::visit_next_statement (next_statement* s) { + visit_statement (s, 1); + if (current_probe == 0) throw semantic_error ("cannot 'next' from function", s->tok); @@ -1437,7 +1466,7 @@ delete_statement_operand_visitor::visit_arrayindex (arrayindex* e) { vector<tmpvar> idx; parent->load_map_indices (e, idx); - parent->o->newline() << "if (unlikely (c->errorcount)) goto out;"; + parent->o->newline() << "if (unlikely (c->last_error)) goto out;"; { mapvar mvar = parent->getmap (e->referent, e->tok); varlock guard (*parent, mvar); @@ -1450,6 +1479,7 @@ delete_statement_operand_visitor::visit_arrayindex (arrayindex* e) void c_unparser::visit_delete_statement (delete_statement* s) { + visit_statement (s, 1); delete_statement_operand_visitor dv (this); s->value->visit (&dv); } @@ -1458,6 +1488,7 @@ c_unparser::visit_delete_statement (delete_statement* s) void c_unparser::visit_break_statement (break_statement* s) { + visit_statement (s, 1); if (loop_break_labels.size() == 0) throw semantic_error ("cannot 'break' outside loop", s->tok); @@ -1469,6 +1500,7 @@ c_unparser::visit_break_statement (break_statement* s) void c_unparser::visit_continue_statement (continue_statement* s) { + visit_statement (s, 1); if (loop_continue_labels.size() == 0) throw semantic_error ("cannot 'continue' outside loop", s->tok); @@ -1552,7 +1584,7 @@ c_unparser::visit_binary_expression (binary_expression* e) o->line() << ";"; o->newline() << ((e->op == "/") ? "_stp_div64" : "_stp_mod64") - << " (&c->errorcount, " << left << ", " << right << ");"; + << " (&c->last_error, " << left << ", " << right << ");"; o->newline(-1) << "})"; } @@ -1634,7 +1666,7 @@ c_unparser::visit_array_in (array_in* e) tmpvar res = gensym (pe_long); - o->newline() << "if (unlikely (c->errorcount)) goto out;"; + o->newline() << "if (unlikely (c->last_error)) goto out;"; { mapvar mvar = getmap (e->operand->referent, e->tok); @@ -1970,7 +2002,7 @@ c_unparser::visit_arrayindex (arrayindex* e) // reentrancy issues that pop up with nested expressions: // e.g. a[a[c]=5] could deadlock - o->newline() << "if (unlikely (c->errorcount)) goto out;"; + o->newline() << "if (unlikely (c->last_error)) goto out;"; { mapvar mvar = getmap (e->referent, e->tok); @@ -2046,7 +2078,7 @@ c_unparser_assignment::visit_arrayindex (arrayindex *e) // reentrancy issues that pop up with nested expressions: // e.g. ++a[a[c]=5] could deadlock - o->newline() << "if (unlikely (c->errorcount)) goto out;"; + o->newline() << "if (unlikely (c->last_error)) goto out;"; prepare_rvalue (op, rvar, e->tok); @@ -2109,9 +2141,10 @@ c_unparser::visit_functioncall (functioncall* e) } o->newline(); - o->newline() << "if (unlikely (c->nesting+2 >= MAXNESTING)) goto out;"; - o->newline() << "c->actioncount ++;"; - o->newline() << "if (unlikely (c->actioncount > MAXACTION)) goto out;"; + o->newline() << "if (unlikely (c->nesting+2 >= MAXNESTING)) {"; + o->newline(1) << "c->last_error = \"MAXNESTING exceeded\";"; + o->newline() << "goto out;"; + o->newline(-1) << "}"; o->newline(); // copy in actual arguments |