public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
* RE: Global constants
@ 2006-02-13 20:13 Stone, Joshua I
  2006-02-13 20:46 ` Frank Ch. Eigler
  0 siblings, 1 reply; 17+ messages in thread
From: Stone, Joshua I @ 2006-02-13 20:13 UTC (permalink / raw)
  To: Frank Ch. Eigler; +Cc: systemtap, Mark McLoughlin

Frank Ch. Eigler wrote:
> The code doesn't need the { } around the printf, and the printf
> doesn't need a semicolon.

Of course this is a matter of coding style, not correctness.  By always
including semicolons and braces, you eliminate ambiguity.  I find it
unfortunate that the language is designed such that the semicolon is
"usually-not but sometimes" needed.

> Perhaps probes consisting of a single statement shouldn't require
> the outer braces either:
>     probe kernel.function ("sys_open") if ($flags & O_CREAT) printf
> ("foo\n") 

I have a negative gut reaction to this as well.  I think if you remove
the braces you start to lose the distinction between a probe declaration
and a statement.  The difference is significant, as only the latter is a
sequential entity.

People moving from conventional programming languages to hardware
languages like VHDL or Verilog are often surprised by the non-sequential
execution.  With the probes in SystemTap, we're not too dissimilar -
probes may fire at any time, completely independent of each other.  I
think we need to enforce some notion that a probe is its own entity, and
the braces do that nicely.


Josh

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 20:13 Global constants Stone, Joshua I
@ 2006-02-13 20:46 ` Frank Ch. Eigler
  0 siblings, 0 replies; 17+ messages in thread
From: Frank Ch. Eigler @ 2006-02-13 20:46 UTC (permalink / raw)
  To: systemtap


joshua.i.stone wrote:

> [...]  I find it unfortunate that the language is designed such that
> the semicolon is "usually-not but sometimes" needed.

It's more like "almost never" needed.  According to my recollection
and testsuite/parseok/elven.stp, it's only needed for disambiguating
overloaded (unary and binary) "+" and "-" operators.

> > Perhaps probes consisting of a single statement shouldn't require
> > the outer braces either: probe kernel.function ("sys_open") if
> > ($flags & O_CREAT) printf ("foo\n")
> 
> I have a negative gut reaction to this as well.  [...]

You've convinced me.

- FChE

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 21:41           ` Martin Hunt
@ 2006-02-14  8:27             ` Mark McLoughlin
  0 siblings, 0 replies; 17+ messages in thread
From: Mark McLoughlin @ 2006-02-14  8:27 UTC (permalink / raw)
  To: Martin Hunt; +Cc: Frank Ch. Eigler, systemtap

[-- Attachment #1: Type: text/plain, Size: 501 bytes --]

On Mon, 2006-02-13 at 13:41 -0800, Martin Hunt wrote:
> On Mon, 2006-02-13 at 20:44 +0000, Mark McLoughlin wrote:

> > 	O_CREAT works fine, but try O_ASYNC (AFAIR)
> 
> Yeah, a quirk of the kernel headers is that they define FASYNC instead
> of the equivalent O_ASYNC. The user headers define both 
> # define FASYNC            O_ASYNC

	Yes, I thought there was another missing value, though. Turns out that
was O_NDCTTY which is merely a typo - it should be O_NOCTTY. Patch
attached.

Cheers,
Mark.

[-- Attachment #2: systemtap-0.5.4-noctty.patch --]
[-- Type: text/x-patch, Size: 755 bytes --]

--- systemtap-0.5.4/tapset/aux_syscalls.stp.noctty	2006-02-14 08:20:02.000000000 +0000
+++ systemtap-0.5.4/tapset/aux_syscalls.stp	2006-02-14 08:20:16.000000000 +0000
@@ -305,7 +305,7 @@
    if(f & 2048) bs="O_NONBLOCK|".bs
    if(f & 1024) bs="O_APPEND|".bs
    if(f & 512)  bs="O_TRUNC|".bs
-   if(f & 256)  bs="O_NDCTTY|".bs
+   if(f & 256)  bs="O_NOCTTY|".bs
    if(f & 128)  bs="O_EXCL|".bs
    if(f & 64)   bs="O_CREAT|".bs
    if((f & 3) == 2) bs="O_RDWR|".bs
@@ -419,7 +419,7 @@
    if(f==2048) return "O_NONBLOCK"
    if(f==1024) return "O_APPEND"
    if(f==512)  return "O_TRUNC"
-   if(f==256)  return "O_NDCTTY"
+   if(f==256)  return "O_NOCTTY"
    if(f==128)  return "O_EXCL"
    if(f==64)   return "O_CREAT"
    if(f==2)    return "O_RDWR"

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 21:50 Stone, Joshua I
@ 2006-02-13 23:50 ` Frank Ch. Eigler
  0 siblings, 0 replies; 17+ messages in thread
From: Frank Ch. Eigler @ 2006-02-13 23:50 UTC (permalink / raw)
  To: Stone, Joshua I; +Cc: systemtap

Hi -

> [...]
> > It's more like "almost never" needed.  [...]
> 
> There's also an ambiguity with '++' and '--', but the testcase
> unfortunately doesn't catch it.  [...]

Ah yes, that's right.  I'll add that to eleven.stp too.
Can you think of any others?

- FChE

^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: Global constants
@ 2006-02-13 22:12 Stone, Joshua I
  0 siblings, 0 replies; 17+ messages in thread
From: Stone, Joshua I @ 2006-02-13 22:12 UTC (permalink / raw)
  To: Frank Ch. Eigler; +Cc: systemtap

Frank Ch. Eigler wrote:
> That would still burden the tapset programmer to add the necessary
> %{ #include <linux/foo.h> %}'s to define all those macros.

Good point.


> [...]
> This could be a plausible solution for bug #1304 (with the addition of
> some type data).  But I would like to aim for something that can be
> set at startup time rather than compile time.  That would be an
> element of bug #2208, where precompiled probe modules may be reused.
> That in turn is more useful if they can be parametrized.

Now that I've looked at those bug #s, I tend to agree - a more general
solution for script parameters is needed.  It's still possible to "fake"
parameters with macros, but given the limitations I don't think we need
more language features around this idea.


Josh

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 20:44         ` Mark McLoughlin
@ 2006-02-13 21:41           ` Martin Hunt
  2006-02-14  8:27             ` Mark McLoughlin
  0 siblings, 1 reply; 17+ messages in thread
From: Martin Hunt @ 2006-02-13 21:41 UTC (permalink / raw)
  To: Mark McLoughlin; +Cc: Frank Ch. Eigler, systemtap

On Mon, 2006-02-13 at 20:44 +0000, Mark McLoughlin wrote:
> On Mon, 2006-02-13 at 12:23 -0800, Martin Hunt wrote:
> > On Mon, 2006-02-13 at 20:14 +0000, Mark McLoughlin wrote:
> > 
> > > > something like
> > > > %{ const_O_CREAT = O_CREAT; %}
> > > >   instead of
> > > > O_CREAT = 64
> > > 
> > > 	Absolutely, that was my first thought too ... unfortunately, the kernel
> > > headers don't seem to have all the values e.g. O_ASYNC is only available
> > > as FASYNC ... I didn't take it any further than thinking "uggh, that
> > > sucks", though :-)
> > 
> > I don't understand.
> > 
> > function get_o_creat:long() %{ THIS->__retvalue = O_CREAT; %}
> > 
> > probe begin {
> > 	printf("O_CREAT = %d\n", get_o_creat())
> > }
> > 
> > > stap -g creat.stp
> > O_CREAT = 64
> 
> 	O_CREAT works fine, but try O_ASYNC (AFAIR)

Yeah, a quirk of the kernel headers is that they define FASYNC instead
of the equivalent O_ASYNC. The user headers define both 
# define FASYNC            O_ASYNC

Martin


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 20:36 Stone, Joshua I
@ 2006-02-13 21:05 ` Frank Ch. Eigler
  0 siblings, 0 replies; 17+ messages in thread
From: Frank Ch. Eigler @ 2006-02-13 21:05 UTC (permalink / raw)
  To: Stone, Joshua I; +Cc: systemtap

Hi -

> Along these same lines, it would be nice to have a more direct way to
> access macros, instead of resorting to embedded-C.  Perhaps something
> like:
> 	import O_CREAT, O_TRUNC, O_APPEND
> The translator could make references to "imported" values as direct
> macro accesses, instead of needing a global systemtap variable.

That would still burden the tapset programmer to add the necessary
%{ #include <linux/foo.h> %}'s to define all those macros.

It would be nice if the kernel were compiled with "-g2" or whatever is
needed to emit macro definitions into DWARF.  Then we could fully
process such things - even expose them as $O_CREAT without an explicit
"import" or "global".


> [...]
> Direct access to macros would make script parameters easy:
> 	# openwatch.stp
> 	import FILE_TO_WATCH
> 	probe syscall.open {
> 	    if (FILE_TO_WATCH == filename)
> [...]

This could be a plausible solution for bug #1304 (with the addition of
some type data).  But I would like to aim for something that can be
set at startup time rather than compile time.  That would be an
element of bug #2208, where precompiled probe modules may be reused.
That in turn is more useful if they can be parametrized.

- FChE

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 20:22       ` Martin Hunt
@ 2006-02-13 20:44         ` Mark McLoughlin
  2006-02-13 21:41           ` Martin Hunt
  0 siblings, 1 reply; 17+ messages in thread
From: Mark McLoughlin @ 2006-02-13 20:44 UTC (permalink / raw)
  To: Martin Hunt; +Cc: Frank Ch. Eigler, systemtap

On Mon, 2006-02-13 at 12:23 -0800, Martin Hunt wrote:
> On Mon, 2006-02-13 at 20:14 +0000, Mark McLoughlin wrote:
> 
> > > something like
> > > %{ const_O_CREAT = O_CREAT; %}
> > >   instead of
> > > O_CREAT = 64
> > 
> > 	Absolutely, that was my first thought too ... unfortunately, the kernel
> > headers don't seem to have all the values e.g. O_ASYNC is only available
> > as FASYNC ... I didn't take it any further than thinking "uggh, that
> > sucks", though :-)
> 
> I don't understand.
> 
> function get_o_creat:long() %{ THIS->__retvalue = O_CREAT; %}
> 
> probe begin {
> 	printf("O_CREAT = %d\n", get_o_creat())
> }
> 
> > stap -g creat.stp
> O_CREAT = 64

	O_CREAT works fine, but try O_ASYNC (AFAIR)

	What header are you including? Maybe you're including the user-space
header? I think I was including linux/fs.h and O_ASYNC wasn't defined.

Cheers,
Mark.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* RE: Global constants
@ 2006-02-13 20:36 Stone, Joshua I
  2006-02-13 21:05 ` Frank Ch. Eigler
  0 siblings, 1 reply; 17+ messages in thread
From: Stone, Joshua I @ 2006-02-13 20:36 UTC (permalink / raw)
  To: Martin Hunt, Frank Ch. Eigler; +Cc: Mark McLoughlin, systemtap

Martin Hunt wrote:
> Also it would be nice to have a way to declare these constants in
> embedded C, so we can use the C header files to get the values, rather
> than look them up.
> 
> something like
> %{ const_O_CREAT = O_CREAT; %}
>   instead of
> O_CREAT = 64

Along these same lines, it would be nice to have a more direct way to
access macros, instead of resorting to embedded-C.  Perhaps something
like:
	import O_CREAT, O_TRUNC, O_APPEND

The translator could make references to "imported" values as direct
macro accesses, instead of needing a global systemtap variable.

There are of course safety issues here - the imported name should be a
macro, and cannot have side-effects.  An #ifndef,#error check fixes the
first, but the second is tricky.  There are also type-safety issues to
consider.

Direct access to macros would make script parameters easy:

	# openwatch.stp
	import FILE_TO_WATCH
	probe syscall.open {
	    if (FILE_TO_WATCH == filename)
	        log(<relevant info>)
	}


	$ stap openwatch.stp -D FILE_TO_WATCH="/etc/passwd"

This can be imitated with an embedded-C function and a begin probe to
read it, but guru-mode shouldn't be required for simple parameter
access.

Josh

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 20:14     ` Mark McLoughlin
@ 2006-02-13 20:22       ` Martin Hunt
  2006-02-13 20:44         ` Mark McLoughlin
  0 siblings, 1 reply; 17+ messages in thread
From: Martin Hunt @ 2006-02-13 20:22 UTC (permalink / raw)
  To: Mark McLoughlin; +Cc: Frank Ch. Eigler, systemtap

On Mon, 2006-02-13 at 20:14 +0000, Mark McLoughlin wrote:

> > something like
> > %{ const_O_CREAT = O_CREAT; %}
> >   instead of
> > O_CREAT = 64
> 
> 	Absolutely, that was my first thought too ... unfortunately, the kernel
> headers don't seem to have all the values e.g. O_ASYNC is only available
> as FASYNC ... I didn't take it any further than thinking "uggh, that
> sucks", though :-)

I don't understand.

function get_o_creat:long() %{ THIS->__retvalue = O_CREAT; %}

probe begin {
	printf("O_CREAT = %d\n", get_o_creat())
}

> stap -g creat.stp
O_CREAT = 64



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 20:10     ` Frank Ch. Eigler
@ 2006-02-13 20:20       ` Mark McLoughlin
  0 siblings, 0 replies; 17+ messages in thread
From: Mark McLoughlin @ 2006-02-13 20:20 UTC (permalink / raw)
  To: Frank Ch. Eigler; +Cc: Martin Hunt, systemtap

Hi,

On Mon, 2006-02-13 at 15:10 -0500, Frank Ch. Eigler wrote:

> > Also it would be nice to have a way to declare these constants in
> > embedded C [...]
> > something like
> > %{ const_O_CREAT = O_CREAT; %}
> >   instead of
> > O_CREAT = 64
> 
> One problem with this is that globals, if elided by the optimizer,
> would still have such references within the opaque embedded-C blocks.
> (That's one of the reasons that embedded-C code should not refer to
> systemtap data other than its arguments.)

	Yep, that's why I initially was doing this:

	In translate.cxx:emit_global()

    ---
       o->newline() << "static rwlock_t "
                    << "global_" << c_varname (v->name) << "_lock;";
    +  o->newline() << "#define global_"
    +               << c_varname(v->name) << "_DEFINED 1";
    ---

	and then

    ---
    global O_CREAT

    function init_sys_open_flags () %{
    #ifdef global_O_CREAT_DEFINED
        global_O_CREAT = 64;
    #endif
    %}
    ---

Cheers,
Mark.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 19:40   ` Martin Hunt
  2006-02-13 20:10     ` Frank Ch. Eigler
@ 2006-02-13 20:14     ` Mark McLoughlin
  2006-02-13 20:22       ` Martin Hunt
  1 sibling, 1 reply; 17+ messages in thread
From: Mark McLoughlin @ 2006-02-13 20:14 UTC (permalink / raw)
  To: Martin Hunt; +Cc: Frank Ch. Eigler, systemtap

Hi Martin,

On Mon, 2006-02-13 at 11:41 -0800, Martin Hunt wrote:

> Also it would be nice to have a way to declare these constants in
> embedded C, so we can use the C header files to get the values, rather
> than look them up.
> 
> something like
> %{ const_O_CREAT = O_CREAT; %}
>   instead of
> O_CREAT = 64

	Absolutely, that was my first thought too ... unfortunately, the kernel
headers don't seem to have all the values e.g. O_ASYNC is only available
as FASYNC ... I didn't take it any further than thinking "uggh, that
sucks", though :-)

Cheers,
Mark.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 19:40   ` Martin Hunt
@ 2006-02-13 20:10     ` Frank Ch. Eigler
  2006-02-13 20:20       ` Mark McLoughlin
  2006-02-13 20:14     ` Mark McLoughlin
  1 sibling, 1 reply; 17+ messages in thread
From: Frank Ch. Eigler @ 2006-02-13 20:10 UTC (permalink / raw)
  To: Martin Hunt; +Cc: Mark McLoughlin, systemtap


hunt wrote:

> [...]
> Hien and I are currently rewriting the syscall tapset, so if constants
> get implemented soon, we can make immediate use of them.  

You could put the current idiom ("global x probe begin { x = 1 }") in
there today.  An emacs macro could transform it to a later form.

> [...]  Declaring variables readonly reduces the probe complexity by
> removing the global locks around all variable access. So it clearly
> seems like a win.

That's a good point.  It turns out that read-only-ness can be inferred
by the translator, so a specific decoration would be only a diagnostic
aid rather than a performance helper.  (The translator would ask
whether this variable only assigned to in a "begin" probe?  While at
it, locks within begin/end probes would be elided since those are run
in isolation.)

> Also it would be nice to have a way to declare these constants in
> embedded C [...]
> something like
> %{ const_O_CREAT = O_CREAT; %}
>   instead of
> O_CREAT = 64

One problem with this is that globals, if elided by the optimizer,
would still have such references within the opaque embedded-C blocks.
(That's one of the reasons that embedded-C code should not refer to
systemtap data other than its arguments.)

- FChE

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 19:28 ` Frank Ch. Eigler
  2006-02-13 19:40   ` Martin Hunt
@ 2006-02-13 20:09   ` Mark McLoughlin
  1 sibling, 0 replies; 17+ messages in thread
From: Mark McLoughlin @ 2006-02-13 20:09 UTC (permalink / raw)
  To: Frank Ch. Eigler; +Cc: systemtap

Hi Frank,

On Mon, 2006-02-13 at 14:28 -0500, Frank Ch. Eigler wrote:

> If the main purpose of this syntax is to compress initialization of
> globals into a single line, one can do it with less effort.  The
> parser could rewrite
>     global var = expr
> to
>     global var; probe begin { var = expr }
> There need be no performance concerns here, partly because the
> optimizer will get rid of any such globals that are not read.

	Does the optimizer currently get rid of such globals? Maybe I missed
something, but I thought it didn't ... wouldn't be hard to fix that
though, granted.

>   It
> could similarly get rid of or merge initialization "begin" probes. 
> 
> Even with this sort of rewriting, if the right hand side of such
> assignments can be an expression, not just a literal, analysis &
> runtime considerations could become complicated.  Consider dependency
> ordering, context setup, error checking, if for example expr is a
> function call dealing with other globals.
> 
> If read-only-ness of these globals is important, then a new "const"
> keyword would indeed come in handy.  (I'd promptly reuse it as a
> qualifier for embedded-C functions that are declared to have no
> side-effects.)  I would implement this angle by a new flag on vardecl,
> enforced non-lvalueness during elaboration or translation, rather than
> whole new staptree.h classes.

	I guess there's a few reasons why I did it this way:

  - The fact that it's read-only means you don't need all the locking 
    that other variables need

  - By only allowing simple literals, you don't have to worry about 
    complexities with evaluating fully fledged expressions at runtime. 
    Although, simple symbol-free expressions like:

      const O_CREAT = 2 << 5

    would probably be a fairly straightforward addition.

  - It's a nice simple syntax for something that would be very useful 
    in the system tapsets

	You guys know best, though :-)

Cheers,
Mark.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 19:28 ` Frank Ch. Eigler
@ 2006-02-13 19:40   ` Martin Hunt
  2006-02-13 20:10     ` Frank Ch. Eigler
  2006-02-13 20:14     ` Mark McLoughlin
  2006-02-13 20:09   ` Mark McLoughlin
  1 sibling, 2 replies; 17+ messages in thread
From: Martin Hunt @ 2006-02-13 19:40 UTC (permalink / raw)
  To: Frank Ch. Eigler; +Cc: Mark McLoughlin, systemtap

On Mon, 2006-02-13 at 14:28 -0500, Frank Ch. Eigler wrote:

> The standard syscalls tapset should define such constants, so end-user
> scripts do not have to.

Hien and I are currently rewriting the syscall tapset, so if constants
get implemented soon, we can make immediate use of them.  


> If read-only-ness of these globals is important, then a new "const"
> keyword would indeed come in handy.  (I'd promptly reuse it as a
> qualifier for embedded-C functions that are declared to have no
> side-effects.)  I would implement this angle by a new flag on vardecl,
> enforced non-lvalueness during elaboration or translation, rather than
> whole new staptree.h classes.

Declaring variables readonly reduces the probe complexity by removing
the global locks around all variable access. So it clearly seems like a
win. 

Also it would be nice to have a way to declare these constants in
embedded C, so we can use the C header files to get the values, rather
than look them up.

something like
%{ const_O_CREAT = O_CREAT; %}
  instead of
O_CREAT = 64

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: Global constants
  2006-02-13 17:39 Mark McLoughlin
@ 2006-02-13 19:28 ` Frank Ch. Eigler
  2006-02-13 19:40   ` Martin Hunt
  2006-02-13 20:09   ` Mark McLoughlin
  0 siblings, 2 replies; 17+ messages in thread
From: Frank Ch. Eigler @ 2006-02-13 19:28 UTC (permalink / raw)
  To: Mark McLoughlin; +Cc: systemtap


Hi, Mark -

markmc wrote:

> [...]
>     const O_CREAT = 64
>     probe kernel.function ("sys_open") {
>         if ($flags & O_CREAT) {
>             printf ("foo\n");
>         }
>     }
>     ---
> Attached is a patch which implements this. [...]

Wow, I commend that you went all the way with your idea to an
implementation.  A few observations though:

The code doesn't need the { } around the printf, and the printf
doesn't need a semicolon.  Perhaps probes consisting of a single
statement shouldn't require the outer braces either:
    probe kernel.function ("sys_open") if ($flags & O_CREAT) printf ("foo\n")

The standard syscalls tapset should define such constants, so end-user
scripts do not have to.

If the main purpose of this syntax is to compress initialization of
globals into a single line, one can do it with less effort.  The
parser could rewrite
    global var = expr
to
    global var; probe begin { var = expr }
There need be no performance concerns here, partly because the
optimizer will get rid of any such globals that are not read.  It
could similarly get rid of or merge initialization "begin" probes. 

Even with this sort of rewriting, if the right hand side of such
assignments can be an expression, not just a literal, analysis &
runtime considerations could become complicated.  Consider dependency
ordering, context setup, error checking, if for example expr is a
function call dealing with other globals.

If read-only-ness of these globals is important, then a new "const"
keyword would indeed come in handy.  (I'd promptly reuse it as a
qualifier for embedded-C functions that are declared to have no
side-effects.)  I would implement this angle by a new flag on vardecl,
enforced non-lvalueness during elaboration or translation, rather than
whole new staptree.h classes.

- FChE

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Global constants
@ 2006-02-13 17:39 Mark McLoughlin
  2006-02-13 19:28 ` Frank Ch. Eigler
  0 siblings, 1 reply; 17+ messages in thread
From: Mark McLoughlin @ 2006-02-13 17:39 UTC (permalink / raw)
  To: systemtap

[-- Attachment #1: Type: text/plain, Size: 1498 bytes --]

Hi,
	Trying out systemtap, I found myself doing the likes of:

    ---
    global O_CREAT

    probe begin {
        O_CREAT = 64
    }

    probe kernel.function ("sys_open") {
        if ($flags & O_CREAT) {
            printf ("foo\n");
        }
    }
    ---

	Then I thought it might be handy to have these kind of globals defined
in the system tapsets so I patched stap with:

    ---
       o->newline() << "static rwlock_t "
                    << "global_" << c_varname (v->name) << "_lock;";
    +  o->newline() << "#define global_"
    +               << c_varname(v->name) << "_DEFINED 1";
    ---

	and put the likes of this in the system tapsets:

    ---
    global O_CREAT

    function init_sys_open_flags () %{
    #ifdef global_O_CREAT_DEFINED
        global_O_CREAT = 64;
    #endif
    %}

    probe begin {
        init_sys_open_flags ();
    }
    ---

	But then I thought that perhaps support for global constants like this
in the language wouldn't be such a bad idea, so you could just do:

    ---
    const O_CREAT = 64

    probe kernel.function ("sys_open") {
        if ($flags & O_CREAT) {
            printf ("foo\n");
        }
    }
    ---

	Attached is a patch which implements this. The patch still needs closer
review, a bit of tidying up, perhaps some more optimisations for
constants, test cases for it in the test suite etc. but it does
basically seem to work. I thought I'd send it here for comments before
finishing it off.

	So, thoughts?

Thanks,
Mark

[-- Attachment #2: systemtap-0.5.4-global-constants.patch --]
[-- Type: text/x-patch, Size: 45568 bytes --]

--- systemtap-0.5.4/parse.h.const	2006-02-13 07:50:25.000000000 +0000
+++ systemtap-0.5.4/parse.h	2006-02-12 09:56:17.000000000 +0000
@@ -118,7 +118,8 @@
 
 private: // nonterminals
   void parse_probe (std::vector<probe*>&, std::vector<probe_alias*>&);
-  void parse_global (std::vector<vardecl*>&);
+  void parse_global (std::vector<symboldecl*>&);
+  void parse_const (std::vector<symboldecl*>&);
   void parse_functiondecl (std::vector<functiondecl*>&);
   embeddedcode* parse_embeddedcode ();
   probe_point* parse_probe_point ();
--- systemtap-0.5.4/staptree.cxx.const	2006-02-13 07:49:59.000000000 +0000
+++ systemtap-0.5.4/staptree.cxx	2006-02-13 10:59:49.000000000 +0000
@@ -89,6 +89,23 @@
 {
 }
 
+
+bool 
+symboldecl::is_var (vardecl *& var_out)
+{
+  var_out = NULL;
+  return false;
+}
+
+
+bool 
+symboldecl::is_const (constdecl *& const_out)
+{
+  const_out = NULL;
+  return false;
+}
+
+
 probe_point::probe_point (std::vector<component*> const & comps,
 			  const token * t):
   components(comps), tok(t) 
@@ -125,6 +142,14 @@
 }
 
 
+bool 
+vardecl::is_var(vardecl *& var_out)
+{
+  var_out = this;
+  return true;
+}
+
+
 void
 vardecl::set_arity (int a)
 {
@@ -152,6 +177,19 @@
 }
 
 
+constdecl::constdecl ()
+{
+}
+
+
+bool 
+constdecl::is_const(constdecl *& const_out)
+{
+  const_out = this;
+  return true;
+}
+
+
 functiondecl::functiondecl ():
   body (0)
 {
@@ -299,6 +337,19 @@
 }
 
 
+void constdecl::print (ostream& o) const
+{
+  o << name << " = ";
+  value->print (o);
+}
+
+
+void constdecl::printsig (ostream& o) const
+{
+  o << name << ":" << type;
+}
+
+
 void functiondecl::print (ostream& o) const
 {
   o << "function " << name << " (";
@@ -776,7 +827,11 @@
 
   for (unsigned i=0; i<globals.size(); i++)
     {
-      o << "global ";
+      constdecl *c;
+      if (globals[i]->is_const (c))
+        o << "const ";
+      else
+        o << "global ";
       globals[i]->print (o);
       o << endl;
     }
@@ -1075,11 +1130,11 @@
 }
 
 void 
-indexable::print_indexable (std::ostream& o) const
+indexable::print_indexable (std::ostream& o)
 {
-  const symbol *sym;
-  const hist_op *hist;
-  classify_const_indexable(this, sym, hist);
+  symbol *sym;
+  hist_op *hist;
+  classify_indexable(this, sym, hist);
   if (sym)
     sym->print (o);
   else
@@ -1120,33 +1175,12 @@
 }
 
 bool 
-indexable::is_const_symbol(const symbol *& sym_out) const
-{
-  sym_out = NULL;
-  return false;
-}
-
-bool 
-indexable::is_const_hist_op(const hist_op *& hist_out) const
-{
-  hist_out = NULL;
-  return false;
-}
-
-bool 
 symbol::is_symbol(symbol *& sym_out)
 {
   sym_out = this;
   return true;
 }
 
-bool 
-symbol::is_const_symbol(const symbol *& sym_out) const
-{
-  sym_out = this;
-  return true;
-}
-
 const token *
 symbol::get_tok() const
 {
@@ -1160,13 +1194,6 @@
   return true;
 }
 
-bool 
-hist_op::is_const_hist_op(const hist_op *& hist_out) const
-{
-  hist_out = this;
-  return true;
-}
-
 const token *
 hist_op::get_tok() const
 {
@@ -1186,17 +1213,6 @@
     throw semantic_error("Failed to classify indexable", ix->get_tok());
 }
 
-void
-classify_const_indexable(const indexable* ix,
-			 const symbol *& array_out,
-			 const hist_op *& hist_out) 
-{
-  array_out = NULL;
-  hist_out = NULL;
-  if (!(ix->is_const_symbol(array_out) || ix->is_const_hist_op(hist_out)))
-    throw semantic_error("Expecting symbol or histogram operator", ix->get_tok());
-}
-
 // ------------------------------------------------------------------------
 
 bool 
--- systemtap-0.5.4/tapset/aux_syscalls.stp.const	2006-02-13 17:23:05.000000000 +0000
+++ systemtap-0.5.4/tapset/aux_syscalls.stp	2006-02-13 17:23:13.000000000 +0000
@@ -298,19 +298,31 @@
    return substr(bs,0,strlen(bs)-1)
 }
 
+const O_ASYNC    = 8192
+const O_SYNC     = 4096
+const O_NONBLOCK = 2048
+const O_APPEND   = 1024
+const O_TRUNC    = 512
+const O_NDCTTY   = 256
+const O_EXCL     = 128
+const O_CREAT    = 64
+const O_RDWR     = 2
+const O_WRONLY   = 1
+const O_RDONLY   = 0
+
 /* `man 2 open` for more information */
 function _sys_open_flag_str(f) {
-   if(f & 8192) bs="O_ASYNC|".bs
-   if(f & 4096) bs="O_SYNC|".bs
-   if(f & 2048) bs="O_NONBLOCK|".bs
-   if(f & 1024) bs="O_APPEND|".bs
-   if(f & 512)  bs="O_TRUNC|".bs
-   if(f & 256)  bs="O_NDCTTY|".bs
-   if(f & 128)  bs="O_EXCL|".bs
-   if(f & 64)   bs="O_CREAT|".bs
-   if((f & 3) == 2) bs="O_RDWR|".bs
-   else if((f & 3) == 1) bs="O_WRONLY|".bs
-   else if((f & 3) == 0) bs="O_RDONLY|".bs
+   if(f & O_ASYNC)    bs="O_ASYNC|".bs
+   if(f & O_SYNC)     bs="O_SYNC|".bs
+   if(f & O_NONBLOCK) bs="O_NONBLOCK|".bs
+   if(f & O_APPEND)   bs="O_APPEND|".bs
+   if(f & O_TRUNC)    bs="O_TRUNC|".bs
+   if(f & O_NDCTTY)   bs="O_NDCTTY|".bs
+   if(f & O_EXCL)     bs="O_EXCL|".bs
+   if(f & O_CREAT)    bs="O_CREAT|".bs
+   if((f & 3) == O_RDWR) bs="O_RDWR|".bs
+   else if((f & 3) == O_WRONLY) bs="O_WRONLY|".bs
+   else if((f & 3) == O_RDONLY) bs="O_RDONLY|".bs
    return substr(bs,0,strlen(bs)-1)
 }
 
--- systemtap-0.5.4/translate.cxx.const	2006-02-13 07:49:44.000000000 +0000
+++ systemtap-0.5.4/translate.cxx	2006-02-13 17:22:44.000000000 +0000
@@ -56,6 +56,8 @@
 }
 
 
+struct sym;
+struct constsym;
 struct var;
 struct tmpvar;
 struct aggvar;
@@ -80,7 +82,8 @@
 
   void emit_map_type_instantiations ();
   void emit_common_header ();
-  void emit_global (vardecl* v);
+  void emit_global_const (constdecl* c);
+  void emit_global_var (vardecl* v);
   void emit_functionsig (functiondecl* v);
   void emit_module_init ();
   void emit_module_exit ();
@@ -123,6 +126,7 @@
   tmpvar gensym(exp_type ty);
   aggvar gensym_aggregate();
 
+  constsym getconst(constdecl* c);
   var getvar(vardecl* v, token const* tok = NULL);
   itervar getiter(symbol* s);
   mapvar getmap(vardecl* v, token const* tok = NULL);
@@ -133,8 +137,10 @@
   void load_aggregate (expression *e, aggvar & agg, bool pre_agg=false);
   string histogram_index_check(var & vase, tmpvar & idx) const;
 
-  void collect_map_index_types(vector<vardecl* > const & vars,
-			       set< pair<vector<exp_type>, exp_type> > & types);
+  void collect_map_index_types_from_syms(vector<symboldecl* > const & syms,
+                                         set< pair<vector<exp_type>, exp_type> > & types);
+  void collect_map_index_types_from_vars(vector<vardecl* > const & vars,
+                                         set< pair<vector<exp_type>, exp_type> > & types);
 
   void visit_statement (statement* s, unsigned actions);
 
@@ -227,7 +233,7 @@
 		       token const*  tok);
 
   void c_assignop(tmpvar & res, 
-		  var const & lvar, 
+		  sym const & lvar, 
 		  tmpvar const & tmp,
 		  token const*  tok);
 
@@ -253,7 +259,47 @@
 };
 
 
-ostream & operator<<(ostream & o, var const & v);
+class sym
+{
+protected:
+  exp_type ty;
+  string name;
+
+public:
+  sym (exp_type type, const string & name)
+    : ty(type), name(name)
+  {}
+  virtual ~sym() {}
+
+  exp_type type() const
+  {
+    return ty;
+  }
+
+  virtual string qname() const = 0;
+};
+
+ostream & operator<<(ostream & o, sym const & s)
+{
+  return o << s.qname();
+}
+
+
+class constsym : public sym
+{
+protected:
+  literal *value;
+
+public:
+  constsym(exp_type type, string const & name, literal* value) 
+    : sym (ty, name), value(value)
+  {}
+
+  string qname() const
+  {
+    return "const_" + name;
+  }
+};
 
 
 /*
@@ -288,25 +334,24 @@
   the user wants to track.  
  */
 
-class var
+class var : public sym
 {
 
 protected:
   bool local;
-  exp_type ty;
   statistic_decl sd;
-  string name;
 
 public:
 
   var(bool local, exp_type ty, statistic_decl const & sd, string const & name)
-    : local(local), ty(ty), sd(sd), name(name)
+    : sym (ty, name), local(local), sd(sd)
   {}
 
   var(bool local, exp_type ty, string const & name)
-    : local(local), ty(ty), name(name)
+    : sym (ty, name), local(local)
   {}
 
+
   virtual ~var() {}
 
   bool is_local() const
@@ -342,11 +387,6 @@
       }
   }
 
-  exp_type type() const
-  {
-    return ty;
-  }
-
   string qname() const
   {
     if (local)
@@ -412,11 +452,6 @@
   }
 };
 
-ostream & operator<<(ostream & o, var const & v)
-{
-  return o << v.qname();
-}
-
 struct stmt_expr
 {
   c_unparser & c;
@@ -963,7 +998,15 @@
 
 
 void
-c_unparser::emit_global (vardecl *v)
+c_unparser::emit_global_const (constdecl *c)
+{
+  o->newline() << "#define const_" << c_varname (c->name) << " ";
+  c->value->visit (this);
+}
+
+
+void
+c_unparser::emit_global_var (vardecl *v)
 {
   if (v->arity == 0)
     o->newline() << "static "
@@ -1056,7 +1099,9 @@
   for (unsigned i=0; i<session->globals.size(); i++)
     {
       // XXX: handle failure!
-      vardecl* v = session->globals[i];      
+      vardecl* v;
+      if (!session->globals[i]->is_var (v))
+        continue;
       if (v->index_types.size() > 0)
 	o->newline() << getmap (v).init();
       else
@@ -1105,8 +1150,8 @@
   // as this is our only chance.
   for (unsigned i=0; i<session->globals.size(); i++)
     {
-      vardecl* v = session->globals[i];      
-      if (v->index_types.size() > 0)
+      vardecl* v;
+      if (session->globals[i]->is_var (v) && v->index_types.size() > 0)
 	o->newline() << getmap (v).fini();
     }
 
@@ -1159,8 +1204,8 @@
 
   for (unsigned i=0; i<session->globals.size(); i++)
     {
-      vardecl* v = session->globals[i];      
-      if (v->index_types.size() > 0)
+      vardecl* v;
+      if (session->globals[i]->is_var (v) && v->index_types.size() > 0)
 	o->newline() << getmap (v).fini();
     }
 
@@ -1296,7 +1341,9 @@
   string last_locked_var;
   for (unsigned i = 0; i < session->globals.size(); i++)
     {
-      vardecl* v = session->globals[i];
+      vardecl* v;
+      if (!session->globals[i]->is_var (v))
+        continue;
       bool read_p = vut.read.find(v) != vut.read.end();
       bool write_p = vut.written.find(v) != vut.written.end();
       if (!read_p && !write_p) continue;
@@ -1344,7 +1391,9 @@
 
   for (int i = session->globals.size()-1; i>=0; i--) // in reverse order!
     {
-      vardecl* v = session->globals[i];
+      vardecl* v;
+      if (!session->globals[i]->is_var (v))
+        continue;
       bool read_p = vut.read.find(v) != vut.read.end();
       bool write_p = vut.written.find(v) != vut.written.end();
       if (!read_p && !write_p) continue;
@@ -1394,8 +1443,22 @@
 
 
 void 
-c_unparser::collect_map_index_types(vector<vardecl *> const & vars,
-				    set< pair<vector<exp_type>, exp_type> > & types)
+c_unparser::collect_map_index_types_from_syms(vector<symboldecl *> const & syms,
+                                              set< pair<vector<exp_type>, exp_type> > & types)
+{
+  for (unsigned i = 0; i < syms.size(); ++i)
+    {
+      vardecl *v;
+      if (syms[i]->is_var (v) && v->arity > 0)
+	{
+	  types.insert(make_pair(v->index_types, v->type));
+	}
+    }
+}
+
+void 
+c_unparser::collect_map_index_types_from_vars(vector<vardecl *> const & vars,
+                                              set< pair<vector<exp_type>, exp_type> > & types)
 {
   for (unsigned i = 0; i < vars.size(); ++i)
     {
@@ -1467,13 +1530,13 @@
 {
   set< pair<vector<exp_type>, exp_type> > types;
   
-  collect_map_index_types(session->globals, types);
+  collect_map_index_types_from_syms(session->globals, types);
 
   for (unsigned i = 0; i < session->probes.size(); ++i)
-    collect_map_index_types(session->probes[i]->locals, types);
+    collect_map_index_types_from_vars(session->probes[i]->locals, types);
 
   for (unsigned i = 0; i < session->functions.size(); ++i)
-    collect_map_index_types(session->functions[i]->locals, types);
+    collect_map_index_types_from_vars(session->functions[i]->locals, types);
 
   if (!types.empty())
     o->newline() << "#include \"alloc.c\"";
@@ -1607,7 +1670,7 @@
 
 void 
 c_unparser_assignment::c_assignop(tmpvar & res, 
-				  var const & lval, 
+				  sym const & lval, 
 				  tmpvar const & rval,
 				  token const * tok)
 {
@@ -1817,6 +1880,13 @@
 }
 
 
+constsym
+c_unparser::getconst(constdecl *c)
+{
+  return constsym (c->type, c->name, c->value);
+}
+
+
 var 
 c_unparser::getvar(vardecl *v, token const *tok) 
 { 
@@ -2094,16 +2164,19 @@
       agg.declare(*(this->parent));
 
       symbol *sym = get_symbol_within_expression (hist->stat);
-      var v = parent->getvar(sym->referent, sym->tok);
-      if (sym->referent->arity != 0)
+      vardecl *rv;
+      sym->referent->is_var (rv);
+      assert (rv);
+      var v = parent->getvar(rv, sym->tok);
+      if (rv->arity != 0)
 	{
 	  arrayindex *arr = NULL;
 	  if (!expression_is_arrayindex (hist->stat, arr))
 	    throw semantic_error("expected arrayindex expression in iterated hist_op", s->tok);
 
-	  for (unsigned i=0; i<sym->referent->index_types.size(); i++)
+	  for (unsigned i=0; i<rv->index_types.size(); i++)
 	    {	      
-	      tmpvar ix = parent->gensym (sym->referent->index_types[i]);
+	      tmpvar ix = parent->gensym (rv->index_types[i]);
 	      ix.declare (*parent);
 	      arr->indexes[i]->visit(this);
 	    }
@@ -2123,8 +2196,12 @@
   if (array)
     {
       visit_statement (s, 1);
+
+      vardecl *rv;
+      array->referent->is_var (rv);
+      assert (rv);
       
-      mapvar mv = getmap (array->referent, s->tok);
+      mapvar mv = getmap (rv, s->tok);
       itervar iv = getiter (array);
       vector<var> keys;
       
@@ -2188,7 +2265,10 @@
       for (unsigned i = 0; i < s->indexes.size(); ++i)
 	{
 	  // copy the iter values into the specified locals
-	  var v = getvar (s->indexes[i]->referent);
+          vardecl* rv;
+          s->indexes[i]->referent->is_var (rv);
+          assert (rv);
+	  var v = getvar (rv);
 	  c_assign (v, iv.get_key (v.type(), i), s->tok);
 	}
       s->block->visit (this);
@@ -2214,13 +2294,20 @@
       // Iterating over buckets in a histogram.
       assert(s->indexes.size() == 1);
       assert(s->indexes[0]->referent->type == pe_long);
-      var bucketvar = getvar (s->indexes[0]->referent);
+
+      vardecl* ri;
+      s->indexes[0]->referent->is_var (ri);
+      assert (ri);
+      var bucketvar = getvar (ri);
 
       aggvar agg = gensym_aggregate ();
       load_aggregate(hist->stat, agg);
 
       symbol *sym = get_symbol_within_expression (hist->stat);
-      var v = getvar(sym->referent, sym->tok);
+      vardecl* rv;
+      sym->referent->is_var(rv);
+      assert(rv);
+      var v = getvar(rv, sym->tok);
       v.assert_hist_compatible(*hist);
 
       // XXX: break / continue don't work here yet
@@ -2292,9 +2379,13 @@
 void 
 delete_statement_operand_visitor::visit_symbol (symbol* e)
 {
-  if (e->referent->arity > 0)
+  vardecl *rv;
+  e->referent->is_var (rv);
+  assert (rv);
+
+  if (rv->arity > 0)
     {
-      mapvar mvar = parent->getmap(e->referent, e->tok);  
+      mapvar mvar = parent->getmap(rv, e->tok);  
       varlock_w guard (*parent, mvar);
       /* NB: such memory deallocation/allocation operations
        are not generally legal in all probe contexts.
@@ -2308,7 +2399,7 @@
     }
   else
     {
-      var v = parent->getvar(e->referent, e->tok);  
+      var v = parent->getvar(rv, e->tok);  
       varlock_w guard (*parent, v);
       switch (e->type)
 	{
@@ -2337,12 +2428,14 @@
 
   if (array)
     {
-      vardecl* r = array->referent;
+      vardecl *rv;
+      array->referent->is_var (rv);
+      assert (rv);
 
       // One temporary per index dimension.
-      for (unsigned i=0; i<r->index_types.size(); i++)
+      for (unsigned i=0; i<rv->index_types.size(); i++)
 	{
-	  tmpvar ix = parent->parent->gensym (r->index_types[i]);
+	  tmpvar ix = parent->parent->gensym (rv->index_types[i]);
 	  ix.declare (*(parent->parent));
 	  e->indexes[i]->visit(parent);
 	}
@@ -2366,7 +2459,11 @@
       parent->load_map_indices (e, idx);
       
       {
-	mapvar mvar = parent->getmap (array->referent, e->tok);
+        vardecl *rv;
+        array->referent->is_var (rv);
+        assert (rv);
+
+	mapvar mvar = parent->getmap (rv, e->tok);
 	varlock_w guard (*parent, mvar);
 	parent->o->newline() << mvar.del (idx) << ";";
       }
@@ -2564,12 +2661,14 @@
   
   if (array)
     {
-      vardecl* r = array->referent;
+      vardecl *rv;
+      array->referent->is_var (rv);
+      assert (rv);
 
       // One temporary per index dimension.
-      for (unsigned i=0; i<r->index_types.size(); i++)
+      for (unsigned i=0; i<rv->index_types.size(); i++)
 	{
-	  tmpvar ix = parent->gensym (r->index_types[i]);
+	  tmpvar ix = parent->gensym (rv->index_types[i]);
 	  ix.declare (*parent);
 	  e->operand->indexes[i]->visit(this);
 	}
@@ -2610,7 +2709,10 @@
       tmpvar res = gensym (pe_long);
       
       { // block used to control varlock_r lifespan
-	mapvar mvar = getmap (array->referent, e->tok);
+        vardecl *rv;
+        array->referent->is_var (rv);
+        assert (rv);
+	mapvar mvar = getmap (rv, e->tok);
 	varlock_r guard (*this, mvar);
 	c_assign (res, mvar.exists(idx), e->tok);
       }
@@ -2803,13 +2905,21 @@
 void
 c_unparser::visit_symbol (symbol* e)
 {
-  vardecl* r = e->referent;
+  vardecl* rv;
 
-  if (r->index_types.size() != 0)
-    throw semantic_error ("invalid reference to array", e->tok);
-
-  var v = getvar(r, e->tok);
-  o->line() << v;
+  if (e->referent->is_var (rv))
+    {
+      if (rv->index_types.size() != 0)
+        throw semantic_error ("invalid reference to array", e->tok);
+      o->line() << getvar(rv, e->tok);
+    }
+  else
+    {
+      constdecl* rc;
+      e->referent->is_const (rc);
+      assert (rc);
+      o->line() << getconst(rc);
+    }
 }
 
 
@@ -2873,9 +2983,11 @@
 void
 c_unparser_assignment::visit_symbol (symbol *e)
 {
+  vardecl *rv;
+
   stmt_expr block(*parent);
 
-  if (e->referent->index_types.size() != 0)
+  if (e->referent->is_var (rv) && rv->index_types.size() != 0)
     throw semantic_error ("unexpected reference to array", e->tok);
 
   parent->o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
@@ -2885,11 +2997,20 @@
 
   prepare_rvalue (op, rval, e->tok);
 
-  {
-    var lvar = parent->getvar (e->referent, e->tok);
-    varlock_w guard (*parent, lvar);
-    c_assignop (res, lvar, rval, e->tok);     
-  }
+  if (rv)
+    {
+      var lvar = parent->getvar (rv, e->tok);
+      varlock_w guard (*parent, lvar);
+      c_assignop (res, lvar, rval, e->tok);     
+    }
+  else
+    {
+      constdecl *rc;
+      e->referent->is_const (rc);
+      assert (rc);
+      constsym lsym = parent->getconst (rc);
+      c_assignop (res, lsym, rval, e->tok);     
+    }
 
   parent->o->newline() << res << ";";
 }
@@ -2914,18 +3035,20 @@
     {
       idx.clear();
       
-      vardecl* r = array->referent;
+      vardecl* rv;
+      array->referent->is_var (rv);
+      assert (rv);
       
-      if (r->index_types.size() == 0 ||
-	  r->index_types.size() != e->indexes.size())
+      if (rv->index_types.size() == 0 ||
+	  rv->index_types.size() != e->indexes.size())
 	throw semantic_error ("invalid array reference", e->tok);
       
-      for (unsigned i=0; i<r->index_types.size(); i++)
+      for (unsigned i=0; i<rv->index_types.size(); i++)
 	{
-	  if (r->index_types[i] != e->indexes[i]->type)
+	  if (rv->index_types[i] != e->indexes[i]->type)
 	    throw semantic_error ("array index type mismatch", e->indexes[i]->tok);
 	  
-	  tmpvar ix = gensym (r->index_types[i]);
+	  tmpvar ix = gensym (rv->index_types[i]);
 	  o->newline() << "c->last_stmt = "
 		       << lex_cast_qstring(*e->indexes[i]->tok) << ";";
 	  c_assign (ix.qname(), e->indexes[i], "array index copy");
@@ -2952,10 +3075,14 @@
   
   if (sym->referent->type != pe_stats)
     throw semantic_error ("unexpected aggregate of non-statistic", sym->tok);
+
+  vardecl *rv;
+  sym->referent->is_var (rv);
+  assert (rv);
   
-  var v = getvar(sym->referent, e->tok);
+  var v = getvar(rv, e->tok);
 
-  if (sym->referent->arity == 0)
+  if (rv->arity == 0)
     {
       o->newline() << "c->last_stmt = " << lex_cast_qstring(*sym->tok) << ";";
       o->newline() << agg << " = _stp_stat_get (" << v << ", 0);";	  
@@ -2968,7 +3095,7 @@
       
       vector<tmpvar> idx;
       load_map_indices (arr, idx);
-      mapvar mvar = getmap (sym->referent, sym->tok);
+      mapvar mvar = getmap (rv, sym->tok);
       o->newline() << "c->last_stmt = " << lex_cast_qstring(*sym->tok) << ";";
       o->newline() << agg << " = " << mvar.get(idx, pre_agg) << ";";
     }
@@ -2992,12 +3119,14 @@
 
   if (array)
     {
-      vardecl* r = array->referent;
+      vardecl* rv;
+      array->referent->is_var (rv);
+      assert (rv);
       
       // One temporary per index dimension.
-      for (unsigned i=0; i<r->index_types.size(); i++)
+      for (unsigned i=0; i<rv->index_types.size(); i++)
 	{
-	  tmpvar ix = parent->gensym (r->index_types[i]);
+	  tmpvar ix = parent->gensym (rv->index_types[i]);
 	  ix.declare (*parent);
 	  e->indexes[i]->visit(this);
 	}
@@ -3054,16 +3183,19 @@
       agg.declare(*(this->parent));
 
       symbol *sym = get_symbol_within_expression (hist->stat);
-      var v = parent->getvar(sym->referent, sym->tok);
-      if (sym->referent->arity != 0)
+      vardecl *rv;
+      sym->referent->is_var (rv);
+      assert (rv);
+      var v = parent->getvar(rv, sym->tok);
+      if (rv->arity != 0)
 	{
 	  arrayindex *arr = NULL;
 	  if (!expression_is_arrayindex (hist->stat, arr))
 	    throw semantic_error("expected arrayindex expression in indexed hist_op", e->tok);
 
-	  for (unsigned i=0; i<sym->referent->index_types.size(); i++)
+	  for (unsigned i=0; i<rv->index_types.size(); i++)
 	    {	      
-	      tmpvar ix = parent->gensym (sym->referent->index_types[i]);
+	      tmpvar ix = parent->gensym (rv->index_types[i]);
 	      ix.declare (*parent);
 	      arr->indexes[i]->visit(this);
 	    }
@@ -3081,8 +3213,12 @@
 
   if (array)
     {
+      vardecl *rv;
+      array->referent->is_var (rv);
+      assert (rv);
+
       // Visiting an statistic-valued array in a non-lvalue context is prohibited.
-      if (array->referent->type == pe_stats)
+      if (rv->type == pe_stats)
 	throw semantic_error ("statistic-valued array in rvalue context", e->tok);
 
       stmt_expr block(*this);  
@@ -3108,7 +3244,7 @@
       // e.g. a[a[c]=5] could deadlock
   
       { // block used to control varlock_r lifespan
-	mapvar mvar = getmap (array->referent, e->tok);
+	mapvar mvar = getmap (rv, e->tok);
 	o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
 	varlock_r guard (*this, mvar);
 	c_assign (res, mvar.get(idx), e->tok);
@@ -3138,12 +3274,15 @@
       assert(idx[0].type() == pe_long);	
 
       symbol *sym = get_symbol_within_expression (hist->stat);
+      vardecl *rv;
+      sym->referent->is_var (rv);
+      assert (rv);
 
       var *v;
-      if (sym->referent->arity < 1)
-	v = new var(getvar(sym->referent, e->tok));
+      if (rv->arity < 1)
+	v = new var(getvar(rv, e->tok));
       else
-	v = new mapvar(getmap(sym->referent, e->tok));
+	v = new mapvar(getmap(rv, e->tok));
 
       v->assert_hist_compatible(*hist);
 
@@ -3199,12 +3338,14 @@
   if (array)
     {
 
-      vardecl* r = array->referent;
+      vardecl* rv;
+      array->referent->is_var (rv);
+      assert (rv);
 
       // One temporary per index dimension.
-      for (unsigned i=0; i<r->index_types.size(); i++)
+      for (unsigned i=0; i<rv->index_types.size(); i++)
 	{
-	  tmpvar ix = parent->parent->gensym (r->index_types[i]);
+	  tmpvar ix = parent->parent->gensym (rv->index_types[i]);
 	  ix.declare (*(parent->parent));
 	  e->indexes[i]->visit(parent);
 	}
@@ -3243,7 +3384,11 @@
 
       translator_output *o = parent->o;
 
-      if (array->referent->index_types.size() == 0)
+      vardecl *rv;
+      array->referent->is_var (rv);
+      assert (rv);
+
+      if (rv->index_types.size() == 0)
 	throw semantic_error ("unexpected reference to scalar", e->tok);
 
       // nb: Do not adjust the order of the next few lines; the tmpvar
@@ -3293,7 +3438,7 @@
 	  assert (e->type == pe_stats);
 	  assert (rvalue->type == pe_long);
 
-	  mapvar mvar = parent->getmap (array->referent, e->tok);
+	  mapvar mvar = parent->getmap (rv, e->tok);
 	  o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
 	  // NB: *no need to* varlock_w guard (*parent, mvar);
 	  o->newline() << mvar.add (idx, rvar) << ";";
@@ -3304,7 +3449,7 @@
 	}
       else
 	{ // block used to control varlock_w lifespan
-	  mapvar mvar = parent->getmap (array->referent, e->tok);
+	  mapvar mvar = parent->getmap (rv, e->tok);
 	  o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
 	  varlock_w guard (*parent, mvar);
 	  if (op != "=") // don't bother fetch slot if we will just overwrite it
@@ -3419,21 +3564,24 @@
   if (e->hist)
     {
       symbol *sym = get_symbol_within_expression (e->hist->stat);
-      var v = parent->getvar(sym->referent, sym->tok);
+      vardecl *rv;
+      sym->referent->is_var (rv);
+      assert (rv);
+      var v = parent->getvar(rv, sym->tok);
       aggvar agg = parent->gensym_aggregate ();
 
       agg.declare(*(this->parent));
 
-      if (sym->referent->arity != 0)
+      if (rv->arity != 0)
 	{
 	  // One temporary per index dimension.
-	  for (unsigned i=0; i<sym->referent->index_types.size(); i++)
+	  for (unsigned i=0; i<rv->index_types.size(); i++)
 	    {
 	      arrayindex *arr = NULL;
 	      if (!expression_is_arrayindex (e->hist->stat, arr))
 		throw semantic_error("expected arrayindex expression in printed hist_op", e->tok);
 	      
-	      tmpvar ix = parent->gensym (sym->referent->index_types[i]);
+	      tmpvar ix = parent->gensym (rv->index_types[i]);
 	      ix.declare (*parent);
 	      arr->indexes[i]->visit(this);
 	    }
@@ -3476,11 +3624,14 @@
       symbol *sym = get_symbol_within_expression (e->hist->stat);
       aggvar agg = gensym_aggregate ();
 
+      vardecl *rv;
+      sym->referent->is_var (rv);
+      assert (rv);
       var *v;
-      if (sym->referent->arity < 1)
-        v = new var(getvar(sym->referent, e->tok));
+      if (rv->arity < 1)
+        v = new var(getvar(rv, e->tok));
       else
-        v = new mapvar(getmap(sym->referent, e->tok));
+        v = new mapvar(getmap(rv, e->tok));
 
       v->assert_hist_compatible(*e->hist);
 
@@ -3607,17 +3758,20 @@
 c_tmpcounter::visit_stat_op (stat_op* e)
 {
   symbol *sym = get_symbol_within_expression (e->stat);
-  var v = parent->getvar(sym->referent, e->tok);
+  vardecl *rv;
+  sym->referent->is_var (rv);
+  assert (rv);
+  var v = parent->getvar(rv, e->tok);
   aggvar agg = parent->gensym_aggregate ();
   tmpvar res = parent->gensym (pe_long);
 
   agg.declare(*(this->parent));
   res.declare(*(this->parent));
 
-  if (sym->referent->arity != 0)
+  if (rv->arity != 0)
     {
       // One temporary per index dimension.
-      for (unsigned i=0; i<sym->referent->index_types.size(); i++)
+      for (unsigned i=0; i<rv->index_types.size(); i++)
 	{
 	  // Sorry about this, but with no dynamic_cast<> and no
 	  // constructor patterns, this is how things work.
@@ -3625,7 +3779,7 @@
 	  if (!expression_is_arrayindex (e->stat, arr))
 	    throw semantic_error("expected arrayindex expression in stat_op of array", e->tok);
 
-	  tmpvar ix = parent->gensym (sym->referent->index_types[i]);
+	  tmpvar ix = parent->gensym (rv->index_types[i]);
 	  ix.declare (*parent);
 	  arr->indexes[i]->visit(this);
 	}
@@ -3654,7 +3808,10 @@
     symbol *sym = get_symbol_within_expression (e->stat);
     aggvar agg = gensym_aggregate ();
     tmpvar res = gensym (pe_long);    
-    var v = getvar(sym->referent, e->tok);
+    vardecl *rv;
+    sym->referent->is_var (rv);
+    assert (rv);
+    var v = getvar(rv, e->tok);
     {
       varlock_w *guard = NULL;
       if (aggregation_locks.count(v.qname()))
@@ -3878,7 +4035,19 @@
       for (unsigned i=0; i<s.globals.size(); i++)
         {
           s.op->newline();
-          s.up->emit_global (s.globals[i]);
+
+          constdecl* c;
+          if (s.globals[i]->is_const (c))
+            s.up->emit_global_const (c);
+        }
+
+      for (unsigned i=0; i<s.globals.size(); i++)
+        {
+          s.op->newline();
+
+          vardecl* v;
+          if (s.globals[i]->is_var (v))
+            s.up->emit_global_var (v);
         }
 
       for (unsigned i=0; i<s.functions.size(); i++)
--- systemtap-0.5.4/translate.h.const	2006-02-13 09:44:11.000000000 +0000
+++ systemtap-0.5.4/translate.h	2006-02-13 16:02:24.000000000 +0000
@@ -66,7 +66,10 @@
   //   } locals [MAXNESTING];
   // } context [MAXCONCURRENCY];
 
-  virtual void emit_global (vardecl* v) = 0;
+  virtual void emit_global_const (constdecl* v) = 0;
+  // #define const_NAME VALUE;
+
+  virtual void emit_global_var (vardecl* v) = 0;
   // static TYPE global_NAME;
   // static rwlock_t global_NAME_lock;
 
--- systemtap-0.5.4/staptree.h.const	2006-02-13 07:50:36.000000000 +0000
+++ systemtap-0.5.4/staptree.h	2006-02-13 11:00:02.000000000 +0000
@@ -181,12 +181,10 @@
   // This is a helper class which, type-wise, acts as a disjoint union
   // of symbols and histograms. You can ask it whether it's a
   // histogram or a symbol, and downcast accordingly.
-  void print_indexable (std::ostream& o) const;
+  void print_indexable (std::ostream& o);
   void visit_indexable (visitor* u);
   virtual bool is_symbol(symbol *& sym_out);
   virtual bool is_hist_op(hist_op *& hist_out);
-  virtual bool is_const_symbol(const symbol *& sym_out) const;
-  virtual bool is_const_hist_op(const hist_op *& hist_out) const;
   virtual const token *get_tok() const = 0;
   virtual ~indexable() {}
 };
@@ -199,24 +197,18 @@
 		   symbol *& array_out,
 		   hist_op *& hist_out);
 
-void
-classify_const_indexable(const indexable* ix,
-			 symbol const *& array_out,
-			 hist_op const *& hist_out);
-
 class vardecl;
 struct symbol:
   public expression,
   public indexable
 {
   std::string name;
-  vardecl *referent;
+  symboldecl *referent;
   symbol ();
   void print (std::ostream& o) const;
   void visit (visitor* u);
   // overrides of type 'indexable'
   const token *get_tok() const;
-  bool is_const_symbol(const symbol *& sym_out) const;
   bool is_symbol(symbol *& sym_out);
 };
 
@@ -358,13 +350,13 @@
   void visit (visitor* u);
   // overrides of type 'indexable'
   const token *get_tok() const;
-  bool is_const_hist_op(const hist_op *& hist_out) const;
   bool is_hist_op(hist_op *& hist_out);
 };
 
 // ------------------------------------------------------------------------
 
 
+class constdecl;
 struct symboldecl // unique object per (possibly implicit)
 		  // symbol declaration
 {
@@ -375,6 +367,8 @@
   virtual ~symboldecl ();
   virtual void print (std::ostream &o) const = 0;
   virtual void printsig (std::ostream &o) const = 0;
+  virtual bool is_var(vardecl *& var_out);
+  virtual bool is_const(constdecl *& const_out);
 };
 
 
@@ -385,6 +379,7 @@
 {
   void print (std::ostream& o) const;
   void printsig (std::ostream& o) const;
+  bool is_var(vardecl *& var_out);
   vardecl ();
   void set_arity (int arity);
   bool compatible_arity (int a);
@@ -398,6 +393,16 @@
 };
 
 
+struct constdecl: public symboldecl
+{
+  void print (std::ostream& o) const;
+  void printsig (std::ostream& o) const;
+  bool is_const(constdecl *& const_out);
+  constdecl ();
+  literal* value;
+};
+
+
 struct statement;
 struct functiondecl: public symboldecl
 {
@@ -536,7 +541,7 @@
   std::vector<probe*> probes;
   std::vector<probe_alias*> aliases;
   std::vector<functiondecl*> functions;
-  std::vector<vardecl*> globals;
+  std::vector<symboldecl*> globals;
   std::vector<embeddedcode*> embeds;
   bool privileged;
   stapfile (): privileged (false) {}
@@ -688,8 +693,8 @@
 // the elaboration-time optimizer pass.
 struct varuse_collecting_visitor: public functioncall_traversing_visitor
 {
-  std::set<vardecl*> read;
-  std::set<vardecl*> written;
+  std::set<symboldecl*> read;
+  std::set<symboldecl*> written;
   bool embedded_seen;
   expression* current_lvalue;
   expression* current_lrvalue;
--- systemtap-0.5.4/session.h.const	2006-02-13 09:43:43.000000000 +0000
+++ systemtap-0.5.4/session.h	2006-02-13 10:26:20.000000000 +0000
@@ -19,7 +19,7 @@
 // forward decls for all referenced systemtap types
 struct match_node;
 struct stapfile;
-struct vardecl;
+struct symboldecl;
 struct functiondecl;
 struct derived_probe;
 struct embeddedcode;
@@ -90,7 +90,7 @@
 
   // resolved globals/functions/probes for the run as a whole
   std::vector<stapfile*> files;
-  std::vector<vardecl*> globals;
+  std::vector<symboldecl*> globals;
   std::vector<functiondecl*> functions;
   std::vector<derived_probe*> probes;
   std::vector<embeddedcode*> embeds;
--- systemtap-0.5.4/parse.cxx.const	2006-02-13 07:49:33.000000000 +0000
+++ systemtap-0.5.4/parse.cxx	2006-02-13 07:53:05.000000000 +0000
@@ -697,6 +697,8 @@
             parse_probe (f->probes, f->aliases);
 	  else if (t->type == tok_identifier && t->content == "global")
 	    parse_global (f->globals);
+	  else if (t->type == tok_identifier && t->content == "const")
+	    parse_const (f->globals);
 	  else if (t->type == tok_identifier && t->content == "function")
             parse_functiondecl (f->functions);
           else if (t->type == tok_embedded)
@@ -910,7 +912,7 @@
 
 
 void
-parser::parse_global (vector <vardecl*>& globals)
+parser::parse_global (vector <symboldecl*>& globals)
 {
   const token* t0 = next ();
   if (! (t0->type == tok_identifier && t0->content == "global"))
@@ -944,6 +946,35 @@
 
 
 void
+parser::parse_const (vector <symboldecl*>& globals)
+{
+  const token* t = next ();
+  if (! (t->type == tok_identifier && t->content == "const"))
+    throw parse_error ("expected 'const'");
+
+  t = next ();
+  if (! (t->type == tok_identifier))
+    throw parse_error ("expected identifier");
+
+  for (unsigned i=0; i<globals.size(); i++)
+    if (globals[i]->name == t->content)
+      throw parse_error ("duplicate global name");
+      
+  constdecl* d = new constdecl;
+  d->name = t->content;
+  d->tok = t;
+  globals.push_back (d);
+
+  t = next ();
+  if (!t || ! (t->type == tok_operator && t->content == "="))
+    throw ("expected '='");
+  
+  d->value = parse_literal ();
+  d->type = d->value->type;
+}
+
+
+void
 parser::parse_functiondecl (std::vector<functiondecl*>& functions)
 {
   const token* t = next ();
--- systemtap-0.5.4/elaborate.h.const	2006-02-13 09:43:56.000000000 +0000
+++ systemtap-0.5.4/elaborate.h	2006-02-13 11:03:23.000000000 +0000
@@ -33,7 +33,7 @@
   derived_probe* current_probe;
   symresolution_info (systemtap_session& s);
 
-  vardecl* find_var (const std::string& name, int arity);
+  symboldecl* find_symboldecl (const std::string& name, bool writable, int arity);
   functiondecl* find_function (const std::string& name, unsigned arity);
 
   void visit_block (block *s);
--- systemtap-0.5.4/elaborate.cxx.const	2006-02-13 07:50:12.000000000 +0000
+++ systemtap-0.5.4/elaborate.cxx	2006-02-13 11:04:16.000000000 +0000
@@ -517,9 +517,14 @@
   {
     if (e->type == pe_stats && e->op == "<<<")
       {
-	vardecl *vd = get_symbol_within_expression (e->left)->referent;
-	if (vd)
-	  mutated_vars->insert (vd);
+	symboldecl *sd = get_symbol_within_expression (e->left)->referent;
+	if (sd)
+          {
+            vardecl *vd;
+            sd->is_var (vd);
+            assert (vd);
+            mutated_vars->insert (vd);
+          }
       }
     traversing_visitor::visit_assignment(e);
   }
@@ -530,7 +535,12 @@
       {
 	symbol *sym;
 	if (e->base->is_symbol (sym))
-	  mutated_vars->insert (sym->referent);
+          {
+            vardecl *vd;
+            sym->referent->is_var (vd);
+            assert (vd);
+            mutated_vars->insert (vd);
+          }
 	else
 	  throw semantic_error("Assignment to read-only histogram bucket", e->tok);
       }
@@ -556,9 +566,12 @@
   {
     if (is_active_lvalue(e))
       {
-	vardecl *vd = get_symbol_within_indexable (e->base)->referent;
-	if (vd)
+	symboldecl *sd = get_symbol_within_indexable (e->base)->referent;
+	if (sd)
 	  {
+            vardecl *vd;
+            sd->is_var (vd);
+            assert (vd);
 	    for (unsigned i = 0; i < vars_being_iterated.size(); ++i)
 	      {
 		vardecl *v = vars_being_iterated[i];
@@ -598,14 +611,19 @@
 
   void visit_foreach_loop(foreach_loop* s)
   {
-    vardecl *vd = get_symbol_within_indexable (s->base)->referent;
+    symboldecl *sd = get_symbol_within_indexable (s->base)->referent;
 
-    if (vd)
-      vars_being_iterated.push_back (vd);
+    if (sd)
+      {
+        vardecl *vd;
+        sd->is_var (vd);
+        assert (vd);
+        vars_being_iterated.push_back (vd);
+      }
     
     traversing_visitor::visit_foreach_loop (s);
 
-    if (vd)
+    if (sd)
       vars_being_iterated.pop_back();
   }
 };
@@ -732,10 +750,9 @@
 
   for (unsigned i = 0; i < sess.globals.size(); ++i)
     {
-      vardecl *v = sess.globals[i];
-      if (v->type == pe_stats)
+      vardecl *v;
+      if (sess.globals[i]->is_var (v) && v->type == pe_stats)
 	{
-	  
 	  if (sess.stat_decls.find(v->name) == sess.stat_decls.end())
 	    {
 	      semantic_error se("unable to infer statistic parameters for global '" + v->name + "'");
@@ -931,7 +948,7 @@
     {
       if (!array->referent)
 	{	  
-	  vardecl* d = find_var (array->name, e->indexes.size ());
+	  symboldecl* d = find_symboldecl (array->name, true, e->indexes.size ());
 	  if (d)
 	    array->referent = d;
 	  else
@@ -972,7 +989,7 @@
     if (e->referent)
       return;
     
-    vardecl* d = parent->find_var (e->name, -1);
+    symboldecl* d = parent->find_symboldecl (e->name, true, -1);
     if (d)
       e->referent = d;
     else
@@ -994,7 +1011,7 @@
   if (e->referent)
     return;
 
-  vardecl* d = find_var (e->name, 0);
+  symboldecl* d = find_symboldecl (e->name, is_active_lvalue (e), 0);
   if (d)
     e->referent = d;
   else
@@ -1030,7 +1047,7 @@
       if (array->referent)
 	return;
 
-      vardecl* d = find_var (array->name, e->indexes.size ());
+      symboldecl* d = find_symboldecl (array->name, true, e->indexes.size ());
       if (d)
 	array->referent = d;
       else
@@ -1075,8 +1092,8 @@
 }
 
 
-vardecl* 
-symresolution_info::find_var (const string& name, int arity)
+symboldecl* 
+symresolution_info::find_symboldecl (const string& name, bool writable, int arity)
 {
 
   // search locals
@@ -1105,11 +1122,21 @@
 
   // search processed globals
   for (unsigned i=0; i<session.globals.size(); i++)
-    if (session.globals[i]->name == name
-	&& session.globals[i]->compatible_arity(arity))  
+    if (session.globals[i]->name == name)
       {
-	session.globals[i]->set_arity (arity);
-	return session.globals[i];
+        vardecl *v;
+        if (session.globals[i]->is_var (v))
+          {
+            if (v->compatible_arity (arity))
+              {
+                v->set_arity (arity);
+                return v;
+              }
+          }
+        else if (!writable)
+          {
+            return session.globals[i];
+          }
       }
   
   // search library globals
@@ -1118,17 +1145,31 @@
       stapfile* f = session.library_files[i];
       for (unsigned j=0; j<f->globals.size(); j++)
         {
-          vardecl* g = f->globals[j];
-          if (g->name == name && g->compatible_arity (arity))
+          if (f->globals[j]->name == name)
             {
-	      g->set_arity (arity);
+              vardecl *g;
+              if (f->globals[j]->is_var (g))
+                {
+                  if (g->compatible_arity (arity))
+                    {
+                      g->set_arity (arity);
+                    }
+                  else
+                    {
+                      continue;
+                    }
+                }
+              else if (writable)
+                {
+                  continue;
+                }
               
               // put library into the queue if not already there	    
               if (find (session.files.begin(), session.files.end(), f) 
                   == session.files.end())
                 session.files.push_back (f);
               
-              return g;
+              return f->globals[j];
             }
         }
     }
@@ -1260,12 +1301,12 @@
       }
   for (unsigned i=0; i<s.globals.size(); /* see below */)
     {
-      vardecl* l = s.globals[i];
+      symboldecl* l = s.globals[i];
       if (vut.read.find (l) == vut.read.end() &&
           vut.written.find (l) == vut.written.end())
         {
           if (s.verbose>2)
-            clog << "Eliding unused global variable "
+            clog << "Eliding unused global symbol "
                  << l->name << endl;
           s.globals.erase(s.globals.begin() + i);
           relaxed_p = false;
@@ -1311,15 +1352,14 @@
 void
 dead_assignment_remover::visit_assignment (assignment* e)
 {
-  symbol* left = get_symbol_within_expression (e->left);
-  vardecl* leftvar = left->referent;
   if (*current_expr == e) // we're not nested any deeper than expected 
     {
-      // clog << "Checking assignment to " << leftvar->name << " at " << *e->tok << endl;
-      if (vut.read.find(leftvar) == vut.read.end()) // var never read?
+      symboldecl* leftsym = get_symbol_within_expression (e->left)->referent;
+      // clog << "Checking assignment to " << leftsym->name << " at " << *e->tok << endl;
+      if (vut.read.find(leftsym) == vut.read.end()) // var never read?
         {
           if (session.verbose>2)
-            clog << "Eliding assignment to " << leftvar->name 
+            clog << "Eliding assignment to " << leftsym->name 
                  << " at " << *e->tok << endl;
           *current_expr = e->right; // goodbye assignment*
           relaxed_p = false;
@@ -1515,7 +1555,7 @@
 
       for (unsigned j=0; j<s.globals.size(); j++)
         {
-          vardecl* gd = s.globals[j];
+          symboldecl* gd = s.globals[j];
           if (gd->type == pe_unknown)
             ti.unresolved (gd->tok);
         }
@@ -1909,18 +1949,22 @@
   assert (array->referent != 0);
   resolve_2types (e, array->referent, this, t);
 
+  vardecl *arraydecl;
+  array->referent->is_var (arraydecl);
+  assert (arraydecl);
+
   // now resolve the array indexes
 
-  // if (e->referent->index_types.size() == 0)
+  // if (arraydecl->index_types.size() == 0)
   //   // redesignate referent as array
-  //   e->referent->set_arity (e->indexes.size ());
+  //   arraydecl->set_arity (e->indexes.size ());
 
-  if (e->indexes.size() != array->referent->index_types.size())
+  if (e->indexes.size() != arraydecl->index_types.size())
     unresolved (e->tok); // symbol resolution should prevent this
   else for (unsigned i=0; i<e->indexes.size(); i++)
     {
       expression* ee = e->indexes[i];
-      exp_type& ft = array->referent->index_types [i];
+      exp_type& ft = arraydecl->index_types [i];
       t = ft;
       ee->visit (this);
       exp_type at = ee->type;
@@ -1929,7 +1973,7 @@
         {
           // propagate to formal type
           ft = at;
-          resolved (array->referent->tok, ft);
+          resolved (arraydecl->tok, ft);
           // uses array decl as there is no token for "formal type"
         }
       if (at == pe_stats)
@@ -2069,13 +2113,16 @@
     }
   else
     {
-      assert (array);  
-      if (e->indexes.size() != array->referent->index_types.size())
+      vardecl *arraydecl;
+      assert (array);
+      array->referent->is_var (arraydecl);
+      assert (arraydecl);
+      if (e->indexes.size() != arraydecl->index_types.size())
 	unresolved (e->tok); // symbol resolution should prevent this
       else for (unsigned i=0; i<e->indexes.size(); i++)
 	{
 	  expression* ee = e->indexes[i];
-	  exp_type& ft = array->referent->index_types [i];
+	  exp_type& ft = arraydecl->index_types [i];
 	  t = ft;
 	  ee->visit (this);
 	  exp_type at = ee->type;
@@ -2084,7 +2131,7 @@
 	    {
 	      // propagate to formal type
 	      ft = at;
-	      resolved (array->referent->tok, ft);
+	      resolved (arraydecl->tok, ft);
 	      // uses array decl as there is no token for "formal type"
 	    }
 	  if (at == pe_stats)
--- systemtap-0.5.4/main.cxx.const	2006-02-13 07:49:21.000000000 +0000
+++ systemtap-0.5.4/main.cxx	2006-02-13 10:59:19.000000000 +0000
@@ -418,11 +418,34 @@
 
   if (rc == 0 && s.last_pass == 2)
     {
-      if (s.globals.size() > 0)
-        cout << "# globals" << endl;
+      bool print_header;
+
+      print_header = true;
+      for (unsigned i=0; i<s.globals.size(); i++)
+	{
+	  constdecl* c;
+          if (!s.globals[i]->is_const (c))
+            continue;
+          if (print_header)
+            {
+              cout << "# constants" << endl;
+              print_header = false;
+            }
+	  c->printsig (cout);
+          cout << endl;
+	}
+
+      print_header = true;
       for (unsigned i=0; i<s.globals.size(); i++)
 	{
-	  vardecl* v = s.globals[i];
+	  vardecl* v;
+          if (!s.globals[i]->is_var (v))
+            continue;
+          if (print_header)
+            {
+              cout << "# globals" << endl;
+              print_header = false;
+            }
 	  v->printsig (cout);
           cout << endl;
 	}
@@ -480,7 +503,7 @@
   if (s.verbose) clog << "Pass 2: analyzed script: "
                       << s.probes.size() << " probe(s), "
                       << s.functions.size() << " function(s), "
-                      << s.globals.size() << " global(s) in "
+                      << s.globals.size() << " global symbol(s) in "
                       << TIMESPRINT
                       << endl;
 

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2006-02-14  8:27 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-02-13 20:13 Global constants Stone, Joshua I
2006-02-13 20:46 ` Frank Ch. Eigler
  -- strict thread matches above, loose matches on Subject: below --
2006-02-13 22:12 Stone, Joshua I
2006-02-13 21:50 Stone, Joshua I
2006-02-13 23:50 ` Frank Ch. Eigler
2006-02-13 20:36 Stone, Joshua I
2006-02-13 21:05 ` Frank Ch. Eigler
2006-02-13 17:39 Mark McLoughlin
2006-02-13 19:28 ` Frank Ch. Eigler
2006-02-13 19:40   ` Martin Hunt
2006-02-13 20:10     ` Frank Ch. Eigler
2006-02-13 20:20       ` Mark McLoughlin
2006-02-13 20:14     ` Mark McLoughlin
2006-02-13 20:22       ` Martin Hunt
2006-02-13 20:44         ` Mark McLoughlin
2006-02-13 21:41           ` Martin Hunt
2006-02-14  8:27             ` Mark McLoughlin
2006-02-13 20:09   ` Mark McLoughlin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).