diff options
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | main.cxx | 1 | ||||
-rw-r--r-- | parse.cxx | 21 | ||||
-rw-r--r-- | runtime/ChangeLog | 6 | ||||
-rw-r--r-- | runtime/arith.c | 79 | ||||
-rw-r--r-- | runtime/builtin_functions.h | 60 | ||||
-rw-r--r-- | runtime/runtime.h | 1 | ||||
-rw-r--r-- | staptree.cxx | 2 | ||||
-rw-r--r-- | staptree.h | 13 | ||||
-rw-r--r-- | tapset/builtin_logging.stp | 20 | ||||
-rwxr-xr-x | testsuite/buildok/eleven.stp | 17 | ||||
-rwxr-xr-x | testsuite/buildok/ten.stp | 14 | ||||
-rwxr-xr-x | testsuite/parseko/six.stp | 1 | ||||
-rwxr-xr-x | testsuite/parseok/six.stp | 12 | ||||
-rwxr-xr-x | testsuite/transok/one.stp | 20 | ||||
-rw-r--r-- | translate.cxx | 57 |
16 files changed, 230 insertions, 112 deletions
@@ -1,3 +1,21 @@ +2005-08-12 Frank Ch. Eigler <fche@elastic.org> + + PR systemtap/1122 et alii + * parse.cxx (parse_literal): Parse and range-limit 64-bit numbers. + (parse_unary): Correct precedence glitch. + * staptree.h (literal_number): Store an int64_t. + * staptree.cxx: Corresponding changes. + * translate.cxx (check_dbz): Remove - insufficient. + (emit_function): Define CONTEXT macro sibling for THIS. + (c_typename): pe_long -> int64_t. + (visit_literal_number): Format literal rigorously and uglily. + (c_assignop, visit_binary_expression): Handle div/mod via new + helper functions in runtime. + * tapset/builtin_logging.stp: Add error, exit builtins. + * testsuite/buildok/ten,eleven.stp: New tests. + * testsuite/parse{ko,ok}/six.stp: Modify for larger numbers. + * testsuite/transok/one.stp: Add more ";"s, maybe unnecessarily. + 2005-08-11 Frank Ch. Eigler <fche@elastic.org> * systemtap.spec.in: Tweak to turn into fedora-flavoured spec. @@ -410,6 +410,7 @@ main (int argc, char * const argv []) cerr << "Pass 4: compilation failed. " << "Try again with '-v' (verbose) option." << endl; + // XXX: what to do if rc==0 && last_pass == 4? dump .ko file to stdout? if (rc || s.last_pass == 4) goto cleanup; // PASS 5: RUN @@ -291,7 +291,7 @@ lexer::scan () return n; } - else if (isdigit (c)) + else if (isdigit (c)) // positive literal { n->type = tok_number; n->content = (char) c; @@ -349,6 +349,11 @@ lexer::scan () string s2 = (c2 > 0 ? s1 + (char) c2 : s1); string s3 = (c3 > 0 ? s2 + (char) c3 : s2); + // NB: if we were to recognize negative numeric literals here, + // we'd introduce another grammar ambiguity: + // 1-1 would be parsed as tok_number(1) and tok_number(-1) + // instead of tok_number(1) tok_operator('-') tok_number(1) + if (s1 == "#") // shell comment { unsigned this_line = cursor_line; @@ -847,15 +852,17 @@ parser::parse_literal () const char* startp = t->content.c_str (); char* endp = (char*) startp; - // NB: we allow controlled overflow from LONG_MIN .. ULONG_MAX + // NB: we allow controlled overflow from LLONG_MIN .. ULLONG_MAX + // Actually, this allows all the way from -ULLONG_MAX to ULLONG_MAX, + // since the lexer only gives us positive digit strings. errno = 0; - long long value = strtoll (startp, & endp, 0); + long long value = (long long) strtoull (startp, & endp, 0); if (errno == ERANGE || errno == EINVAL || *endp != '\0' - || value > 4294967295LL || value < (-2147483647LL-1)) + || (unsigned long long) value > 18446744073709551615ULL + || value < -9223372036854775807LL-1) throw parse_error ("number invalid or out of range"); - long value2 = (long) value; - l = new literal_number (value2); + l = new literal_number (value); } else throw parse_error ("expected literal string or number"); @@ -1537,7 +1544,7 @@ parser::parse_unary () e->op = t->content; e->tok = t; next (); - e->operand = parse_expression (); + e->operand = parse_crement (); return e; } else diff --git a/runtime/ChangeLog b/runtime/ChangeLog index fe6fe13b..c0e2ac65 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,9 @@ +2005-08-12 Frank Ch. Eigler <fche@elastic.org> + + * arith.c: New file to contain arithmetic helper functions. + * builtin_functions.h: Remove, unused. + * runtime.h: Include it. + 2005-08-10 Roland McGrath <roland@redhat.com> * loc2c-runtime.h (store_bitfield): Fix argument use. diff --git a/runtime/arith.c b/runtime/arith.c new file mode 100644 index 00000000..175cc4e8 --- /dev/null +++ b/runtime/arith.c @@ -0,0 +1,79 @@ +#ifndef _ARITH_C_ /* -*- linux-c -*- */ +#define _ARITH_C_ + +/** @file arith. + * @brief Implements 64-bit signed division/multiplication. + */ + +struct context; +void _stp_divmod64 (unsigned *errorcount, 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. + */ +inline int64_t _stp_div64 (unsigned *errorcount, int64_t x, int64_t y) +{ + if (likely ((x >= LONG_MIN && x <= LONG_MAX) && + (y >= LONG_MIN && y <= LONG_MAX))) + { + long xx = (long) x; + long yy = (long) y; + // check for division-by-zero and overflow + if (unlikely (yy == 0 || (xx == LONG_MIN && yy == -1))) + { + (*errorcount) ++; + return 0; + } + return xx / yy; + } + else + { + int64_t quo = 0; + _stp_divmod64 (errorcount, 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. + */ +inline int64_t _stp_mod64 (unsigned *errorcount, int64_t x, int64_t y) +{ + if (likely ((x >= LONG_MIN && x <= LONG_MAX) && + (y >= LONG_MIN && y <= LONG_MAX))) + { + long xx = (long) x; + long yy = (long) y; + // check for division-by-zero and overflow + if (unlikely (yy == 0 || (xx == LONG_MIN && yy == -1))) + { + (*errorcount) ++; + return 0; + } + return xx % yy; + } + else + { + int64_t rem = 0; + _stp_divmod64 (errorcount, x, y, NULL, &rem); + return rem; + } +} + + +/** Perform general long division/modulus. */ +void _stp_divmod64 (unsigned *errorcount, int64_t x, int64_t y, + int64_t *quo, int64_t *rem) +{ + // XXX: wimp out for now + (*errorcount) ++; + if (quo) *quo = 0; + if (rem) *rem = 0; +} + + + +#endif /* _ARITH_C_ */ diff --git a/runtime/builtin_functions.h b/runtime/builtin_functions.h deleted file mode 100644 index 505d073b..00000000 --- a/runtime/builtin_functions.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _BUILTIN_FUNCTIONS_ -#define _BUILTIN_FUNCTIONS_ - -/* Builtin function definitions. - * Copyright (C) 2005 Red Hat Inc. - * - * This file is part of systemtap, and is free software. You can - * redistribute it and/or modify it under the terms of the GNU General - * Public License (GPL); either version 2, or (at your option) any - * later version. - */ - -/* - * This file contains definitions for "builtin functions" which are - * registered in the systemtap translator, but given no definition. - * The translator emits calls to builtins exactly the same way it - * emits calls to functions written in the systemtap language; the - * only difference is that this file (or a C tapset) must supply the - * definition. - * - * Every builtin function "foo" called by a systemtap script is - * translated to a C call to a C function named "function_foo". This - * is the function you must provide in this file. In addition, the - * translator emits a - * - * #define _BUILTIN_FUNCTION_foo_ - * - * symbol for each such function called, which you can use to elide - * function definitions which are not used by a given systemtap - * script. - */ - -#ifdef _BUILTIN_FUNCTION_printk_ -static void -function_printk (struct context *c) -{ - printk (KERN_INFO "%s\n", c->locals[c->nesting].function_printk.message); -} -#endif /* _BUILTIN_FUNCTION_printk_ */ - - -#ifdef _BUILTIN_FUNCTION_log_ -static void -function_log (struct context *c) -{ - _stp_log (c->locals[c->nesting].function_log.message); -} -#endif /* _BUILTIN_FUNCTION_log_ */ - - -#ifdef _BUILTIN_FUNCTION_warn_ -static void -function_warn (struct context *c) -{ - _stp_warn (c->locals[c->nesting].function_warn.message); -} -#endif /* _BUILTIN_FUNCTION_warn_ */ - - -#endif /* _BUILTIN_FUNCTIONS_ */ diff --git a/runtime/runtime.h b/runtime/runtime.h index 5903bede..549738e1 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -55,6 +55,7 @@ static struct #include "print.c" #include "string.c" +#include "arith.c" /************* Module Stuff ********************/ int probe_start(void); diff --git a/staptree.cxx b/staptree.cxx index 811605ca..eb811e49 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -136,7 +136,7 @@ functiondecl::functiondecl (): } -literal_number::literal_number (long v) +literal_number::literal_number (int64_t v) { value = v; type = pe_long; @@ -14,7 +14,9 @@ #include <vector> #include <iostream> #include <stdexcept> - +extern "C" { +#include <stdint.h> +} struct token; // parse.h struct semantic_error: public std::runtime_error @@ -38,8 +40,8 @@ struct semantic_error: public std::runtime_error enum exp_type { pe_unknown, - pe_long, - pe_string, + pe_long, // int64_t + pe_string, // std::string pe_stats }; @@ -77,9 +79,8 @@ struct literal_string: public literal struct literal_number: public literal { - // XXX: s/long/long long/ throughout - long value; - literal_number (long v); + int64_t value; + literal_number (int64_t v); void print (std::ostream& o); void visit (visitor* u); }; diff --git a/tapset/builtin_logging.stp b/tapset/builtin_logging.stp index 51fb97e4..11b00cab 100644 --- a/tapset/builtin_logging.stp +++ b/tapset/builtin_logging.stp @@ -1,3 +1,5 @@ +# This file contains simple bridging functions to the runtime + function _log (msg) %{ _stp_log (THIS->msg); %} @@ -5,6 +7,7 @@ function _log (msg) %{ function log (msg) { _log (msg . "") } + function _printk (msg) %{ printk (KERN_INFO "%s\n", THIS->msg); %} @@ -12,10 +15,25 @@ function _printk (msg) %{ function printk (msg) { _printk (msg . "") } + function _warn (msg) %{ - _stp_warn (THIS->msg); + _stp_warn ("%s", THIS->msg); %} function warn (msg) { _warn (msg . "") } + +function exit () %{ + CONTEXT->errorcount ++; /* kill current probe */ + _stp_exit (); +%} + +function _error (msg) %{ + CONTEXT->errorcount ++; /* kill current probe */ + _stp_error ("%s", THIS->msg); /* implies _stp_exit */ +%} + +function error (msg) { + _error (msg . "") +} diff --git a/testsuite/buildok/eleven.stp b/testsuite/buildok/eleven.stp new file mode 100755 index 00000000..66d4a318 --- /dev/null +++ b/testsuite/buildok/eleven.stp @@ -0,0 +1,17 @@ +#! stap -p4 + +probe begin +{ + a = -1 / -1; + b = 2147483647; + c = 4294967295 / a; + d = (-2147483647-1) % c; + e = 9223372036854775807 * b; + d /= b % e; + b %= 0 / f; + x = 1 / 0; +} +probe end +{ + y %= 0; +} diff --git a/testsuite/buildok/ten.stp b/testsuite/buildok/ten.stp new file mode 100755 index 00000000..6015fbb9 --- /dev/null +++ b/testsuite/buildok/ten.stp @@ -0,0 +1,14 @@ +#! stap -p4 + +probe begin +{ + a = 1+01+0x1-1-01-0x1; + + long_max = 2147483647; + ulong_max = 4294967295; + long_min = -2147483647-1; + + llong_max = 9223372036854775807; + ullong_max = 18446744073709551615; + llong_min = -9223372036854775807-1; +} diff --git a/testsuite/parseko/six.stp b/testsuite/parseko/six.stp index f37cd034..803d864c 100755 --- a/testsuite/parseko/six.stp +++ b/testsuite/parseko/six.stp @@ -5,4 +5,5 @@ probe foo { b = 0xzoopoo; c = 00011122233344455566677788; d = 07777777777777777777777777; + e = 18446744073709551616; # ULLONG_MAX+1 } diff --git a/testsuite/parseok/six.stp b/testsuite/parseok/six.stp index bc16a336..5c3d7866 100755 --- a/testsuite/parseok/six.stp +++ b/testsuite/parseok/six.stp @@ -1,8 +1,14 @@ #! stap -p1 -probe one +probe nothing { a = 1+01+0x1-1-01-0x1; - b = 2147483647; - c = -2147483647-1; + + long_max = 2147483647; + ulong_max = 4294967295; + long_min = -2147483647-1; + + llong_max = 9223372036854775807; + ullong_max = 18446744073709551615; + llong_min = -9223372036854775807-1; } diff --git a/testsuite/transok/one.stp b/testsuite/transok/one.stp index 6c624f14..7da27549 100755 --- a/testsuite/transok/one.stp +++ b/testsuite/transok/one.stp @@ -42,15 +42,13 @@ probe begin a / b a % b - # all unary operators - a ++ - a -- - -- a - -- b - ~ a - ! a - ; # grammar glitch - + a - ; # grammar glitch - - a + # all unary operators; use explicit ";" to avoid grammar ambiguities + a ++ ; + a -- ; + ++ a ; + -- b ; + ~ a ; + ! a ; + + a ; + - a ; } diff --git a/translate.cxx b/translate.cxx index b2a44563..6b3ee308 100644 --- a/translate.cxx +++ b/translate.cxx @@ -236,17 +236,6 @@ public: return "global_" + name; } - void check_dbz(c_unparser &c) const - { - if (ty == pe_long) - { - c.o->newline() << "if (unlikely (" << qname() << " == 0)) {"; - c.o->newline(1) << "c->errorcount++;"; - c.o->newline() << qname() << " = 1;"; - c.o->newline(-1) << "}"; - } - } - string init() const { switch (type()) @@ -752,10 +741,12 @@ c_unparser::emit_function (functiondecl* v) << "& c->locals[c->nesting].function_" << c_varname (v->name) << ";"; o->newline(-1) << "(void) l;"; // make sure "l" is marked used + o->newline() << "#define CONTEXT c"; o->newline() << "#define THIS l"; o->newline() << "if (0) goto out;"; // make sure out: is marked used // initialize locals + // XXX: optimization: use memset instead for (unsigned i=0; i<v->locals.size(); i++) { if (v->locals[i]->index_types.size() > 0) // array? @@ -780,6 +771,7 @@ c_unparser::emit_function (functiondecl* v) o->newline(-1) << "out:"; o->newline(1) << ";"; + o->newline() << "#undef CONTEXT"; o->newline() << "#undef THIS"; o->newline(-1) << "}" << endl; } @@ -951,7 +943,7 @@ c_unparser::c_typename (exp_type e) { switch (e) { - case pe_long: return string("long"); + case pe_long: return string("int64_t"); case pe_string: return string("string_t"); case pe_stats: return string("stats_t"); case pe_unknown: @@ -1076,12 +1068,13 @@ c_unparser_assignment::c_assignop(tmpvar & res, // - stats aggregation "<<<" // - modify-accumulate "+=" and many friends // - pre/post-crement "++"/"--" + // - "/" and "%" operators, but these need special handling in kernel // compute the modify portion of a modify-accumulate string macop; unsigned oplen = op.size(); if (op == "=") - macop = "* 0 +"; // clever (?) trick to select rvalue (tmp) only + macop = "*error*"; // special shortcuts below else if (oplen > 1 && op[oplen-1] == '=') // for +=, %=, <<=, etc... macop = op.substr(0, oplen-1); else if (op == "<<<") @@ -1093,16 +1086,35 @@ c_unparser_assignment::c_assignop(tmpvar & res, else // internal error throw semantic_error ("unknown macop for assignment", tok); - + if (pre) { + if (macop == "/" || macop == "%" || op == "=") + throw semantic_error ("invalid pre-mode operator", tok); + o->newline() << res << " = " << lval << ";"; - o->newline() << lval << " = " << res << " " << macop << " " << rval << ";"; + o->newline() << lval << " = " << res << " " << macop << " " << rval << ";"; } else { - o->newline() << res << " = " << lval << " " << macop << " " << rval << ";"; - o->newline() << lval << " = " << res << ";"; + if (op == "=") // shortcut simple assignment + { + o->newline() << lval << " = " << rval << ";"; + res = rval; + } + else + { + if (macop == "/") + o->newline() << res << " = _stp_div64 (&c->errorcount, " + << lval << ", " << rval << ");"; + else if (macop == "%") + o->newline() << res << " = _stp_mod64 (&c->errorcount, " + << lval << ", " << rval << ");"; + else + o->newline() << res << " = " << lval << " " << macop << " " << rval << ";"; + + o->newline() << lval << " = " << res << ";"; + } } } else @@ -1471,7 +1483,9 @@ c_unparser::visit_literal_string (literal_string* e) void c_unparser::visit_literal_number (literal_number* e) { - o->line() << e->value; + // This looks ugly, but tries to be warning-free on 32- and 64-bit + // hosts. + o->line() << "((uint64_t)" << e->value << "LL)"; } @@ -1532,9 +1546,9 @@ c_unparser::visit_binary_expression (binary_expression* e) e->right->visit (this); o->line() << ";"; - right.check_dbz(*this); + o->newline() << ((e->op == "/") ? "_stp_div64" : "_stp_mod64") + << " (&c->errorcount, " << left << ", " << right << ");"; - o->newline() << left << " " << e->op << " " << right << ";"; o->newline(-1) << "})"; } else @@ -1815,9 +1829,6 @@ c_unparser_assignment::prepare_rvalue (string const & op, throw semantic_error ("need rvalue for assignment", tok); } // OPT: literal rvalues could be used without a tmp* copy - - if (op == "/=" || op == "%=") - rval.check_dbz (*parent); } void |