Setting Breakpoints
In many cases, your knowledge of what a program is doing lets you make predictions as to where problems will occur. The following CLI macro parses comments that you can include within a source file and, depending on the comment's text, sets a breakpoint or an evaluation point.
Immediately following this listing is an excerpt from a program that uses this macro.
# make_actions: Parse a source file, and insert
# evaluation and breakpoints according to comments.
#
proc make_actions { { filename "" } } {
if { $filename == "" } {
puts "You need to specify a filename"
error "No filename"
}
# Open the program's source file and initialize a
# few variables.
set fname [set filename]
set fsource [open $fname r]
set lineno 0
set incomment 0
# Look for "signals" that indicate the kind of action
# point; they are buried in the C comments.
while { [gets $fsource line] != -1} {
incr lineno
set bpline $lineno
# Look for a one-line evaluation point. The
# format is ... /* EVAL: some_text */.
# The text after EVAL and before the "*/" in
# the comment is assigned to "code".
if [regexp "/\\* EVAL: *(.*)\\*/" $line all code] {
dbreak $fname\#$bpline -e $code
continue
}
# Look for a multiline evaluation point.
if [regexp "/\\* EVAL: *(.*)" $line all code] {
# Append lines to "code".
while { [gets $fsource interiorline] != -1} {
incr lineno
# Tabs will confuse dbreak.
regsub -all \t $interiorline " " interiorline
# If "*/" is found, add the text to "code", then
# leave the loop. Otherwise, add the text, and
# continue looping.
if [regexp "(.*)\\*/" $interiorline all interiorcode]{
append code \n $interiorcode
break
} else {
append code \n $interiorline
}
}
dbreak $fname\#$bpline -e $code
continue
}
# Look for a breakpoint.
if [regexp "/\\* STOP: .*" $line] {
dbreak $fname\#$bpline
continue
}
# Look for a command to be executed by Tcl.
if [regexp "/\\* *CMD: *(.*)\\*/" $line all cmd] {
puts "CMD: [set cmd]"
eval $cmd
}
}
close $fsource
}
The only similarity between this example and the previous two is that almost all of the statements are Tcl. The only purely CLI commands are the instances of the dbreak command. (This command sets evaluation points and breakpoints.)
The following excerpt from a larger program shows how you would embed comments within a source file that would be read by this macro:
...
struct struct_bit_fields_only {
unsigned f3 : 3;
unsigned f4 : 4;
unsigned f5 : 5;
unsigned f20 : 20;
unsigned f32 : 32;
} sbfo, *sbfop = &sbfo;
...
int main()
{
struct struct_bit_fields_only *lbfop = &sbfo;
...
int i;
int j;
sbfo.f3 = 3;
sbfo.f4 = 4;
sbfo.f5 = 5;
sbfo.f20 = 20;
sbfo.f32 = 32;
...
/* TEST: Check to see if we can access all the values */
i=i; /* STOP: // Should stop */
i=1; /* EVAL: if (sbfo.f3 != 3) $stop; // Should not stop */
i=2; /* EVAL: if (sbfo.f4 != 4) $stop; // Should not stop */
i=3; /* EVAL: if (sbfo.f5 != 5) $stop; // Should not stop */
...
return 0;
}
The make_actions macro reads a source file one line at a time. As it reads these lines, the regular expressions look for comments that begin with /* STOP, /* EVAL, and /* CMD. After parsing the comment, it sets a breakpoint at a stop line, an evaluation points at an eval line, or executes a command at a cmd line.
Using evaluation points can be confusing because evaluation point syntax differs from that of Tcl. In this example, the $stop command is a command contained within TotalView (and the CLI). It is not a Tcl variable. In other cases, the evaluation statements will be in the C or Fortran programming languages.