summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog18
-rw-r--r--main.cxx1
-rw-r--r--parse.cxx21
-rw-r--r--runtime/ChangeLog6
-rw-r--r--runtime/arith.c79
-rw-r--r--runtime/builtin_functions.h60
-rw-r--r--runtime/runtime.h1
-rw-r--r--staptree.cxx2
-rw-r--r--staptree.h13
-rw-r--r--tapset/builtin_logging.stp20
-rwxr-xr-xtestsuite/buildok/eleven.stp17
-rwxr-xr-xtestsuite/buildok/ten.stp14
-rwxr-xr-xtestsuite/parseko/six.stp1
-rwxr-xr-xtestsuite/parseok/six.stp12
-rwxr-xr-xtestsuite/transok/one.stp20
-rw-r--r--translate.cxx57
16 files changed, 230 insertions, 112 deletions
diff --git a/ChangeLog b/ChangeLog
index a0d3f422..41f99906 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/main.cxx b/main.cxx
index 390816af..99be67da 100644
--- a/main.cxx
+++ b/main.cxx
@@ -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
diff --git a/parse.cxx b/parse.cxx
index c4098562..15f2b0f1 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -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;
diff --git a/staptree.h b/staptree.h
index 93537921..8edb3ecc 100644
--- a/staptree.h
+++ b/staptree.h
@@ -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