Debugging support for Maisie programs is provided in two ways. First,
by appropriately inserting two special Maisie constructs, called
printmsg and trace, in the Maisie program, the user can
monitor the execution of the program. The second alternative is to use
the traditional source-level debuggers like dbx available
with UNIX to step through the Maisie program. Rest of the section
describes these features in detail.
It may be useful to examine the messages in an entity's message queue
at a given point during execution. Maisie provides a function called
printmsg(
) which
prints out all messages in the message queue of the calling entity
that are of type
. The
messages are printed in the order of the ranker associated
with the last resume-condition in which mtype(
) is used, or by default in increasing timestamp
order. If
is omitted, all
messages in the message queue are printed in increasing timestamp
order. In the following examples, the first one prints all messages in
timestamp order; the second prints all request messages in
the message queue.
Example:printmsg(); /* print all messages */ printmsg(request); /* print request messages */
Maisie provides a simple trace facility to aid program debugging.
trace-st ::= trace value when condition; value ::= a C expression of type int condition ::= a C boolean expression (side-effect free)
An entity evaluates each condition in its body whenever a message is received. Depending on the value, the entity reacts differently.
The following examples illustrate the use of the trace facility. The statement in the first example causes the values of all non-array local variables of the receiving entity to be printed to stdout whenever a message is received. The second example illustrates that when the received message is of type request, its content is printed to stdout. The trace-statement in the third example prints out all messages but only when the variable myid is equal to 2.
Example:trace 2; trace 1 when mtype(request); trace 1 when (myid == 2);
An entity definition may have more than one trace statement. The trace conditions are evaluated in the order that they appear in the entity body. The trace value specified in the first condition which evaluates to true determines the level of tracing to be performed for the entity. If all conditions evaluate to false, nothing will be printed.
Remarks:
Maisie defines a message type trace_msg for every entity. The message has a single parameter, trace_val, of type int. The value of trace_val determines the level at which tracing is to be performed in the receiving entity. The trace information will be printed for every subsequent message received by the entity. The level of tracing can only be changed by receiving another trace_msg message. The trace statement and message operate independently. If the two trace levels are different for a given entity instance, the larger of the two defines the tracing level.
A Maisie program is translated into a C program which is then compiled using a C compiler. It is possible to debug at the level of Maisie source using a standard Unix C debugger. The program needs to be compiled using the '-g' flag. The entity parameters and local variables are renamed according to the following conventions:
The global variables, and variables and parameters declared within a function are not renamed. Compiler defined variables (e.g. self, msg) are not renamed.
Example:entity XX { a } int a; /* a ==> zzp0->a */ { int b[5],i; /* b ==> zzp1->b, i unchanged */ int search(); /* search ==> _XX_search */ for(i =0; i < 5 ; ++) { int j; /* j ==> zzp2->j */ ... } } int XX::search(v) /* ==> _XX_search(v) */ int v; /* v unchanged */ { int i; /* i unchanged */ for(i =0; i < 5 ; ++) if(v == b[i ]) /* b ==> zzp1->b */ ... }
Below, we show a sample Maisie program, and how it is compiled, executed, and debugged in a dbx session. As seen in the program, line 8 will cause the program execution to have segmentation violation due to an incorrect array reference. Lines 34-37 show that parameter a of entity XX and local variable b may not be accessed directly. However, as seen in the listing, a has been renamed to zzp0->a, and variable b has been renamed to zzp1->b, and entity XX is actually the function XX.
[1] #include "maisie.h"
[2]
[3] entity XX{ a }
[4] int a;
[5] { int b[5],i;
[6] for(i=0; i< 5; i++)
[7] b[i] = i;
[8] b[a] ++;
[9] }
[10]
[11] entity driver{}
[12] {
[13] new XX{10000};
[14] }
Debugging: The sample program (sample.m)
[24] % mc -P -g sample.m
[25] % a.out
[26] Segmentation fault
[27] % dbx a.out
[28] Reading symbolic information...
[29] Read 1482 symbols
[30] (dbx) run
[31] Running: a.out
[32] signal SEGV (no mapping at the fault address) in ...
[33] 8 b[a] ++;
[34] (dbx) print b
[35] "b" is not defined
[36] (dbx) print a
[37] "a" is not defined
[38] (dbx) print zzp1->b
[39] zzp1->b = (0, 1, 2, 3, 4)
[40] (dbx) p zzp0->a
[41] `sample`XX`zzp0->a = 10000
Debugging: Using dbx
Runtime errors/warnings are detected by Maisie and appropriate messages are send to stderr. Some of the common errors/warnings are: