HP OpenVMS Systems Documentation
OpenVMS Debugger Manual
2.3.4 Suspending Program Execution with Breakpoints
The SET BREAK command enables you to select locations at which to suspend program execution (breakpoints). You can then enter commands to check the call stack, examine the current values of variables, and so on. You resume execution from a breakpoint with the GO or STEP commands.
The following example shows a typical use of the SET BREAK command:
In the example, the SET BREAK command sets a breakpoint on routine COUNT (at the beginning of the routine's code); the GO command starts execution. When routine COUNT is encountered, the following occurs:
At this breakpoint, you can use the STEP command to step through routine COUNT and then use the EXAMINE command (discussed in Section 2.4.1) to check on the values of X and Y.
When using the SET BREAK command, you can specify program locations using various kinds of address expressions (for example, line numbers, routine names, memory addresses, byte offsets). With high-level languages, you typically use routine names, labels, or line numbers, possibly with path names to ensure uniqueness.
Specify routine names and labels as they appear in the source code. Line numbers can be derived from either a source code display or a listing file. When specifying a line number, use the prefix %LINE; otherwise, the debugger interprets the line number as a memory location. For example, the following command sets a breakpoint at line 41 of the module in which execution is paused. The breakpoint causes the debugger to suspend execution at the beginning of line 41.
Note that you can set breakpoints only on lines that resulted in machine-code instructions. The debugger warns you if you try to do otherwise (for example, on a comment line). To pick a line number in a module other than the one in which execution is paused, you must specify the module's name in a path name. For example:
You can also use the SET BREAK command with a qualifier, but no parameter, to break on every line, or on every CALL instruction, and so on. For example:
You can set breakpoints on events, such as exceptions, or state transitions in tasking programs.
You can conditionalize a breakpoint (with a WHEN clause) or specify that a list of commands be executed at the breakpoint (with a DO clause).
To display the current breakpoints, enter the SHOW BREAK command.
To deactivate a breakpoint, enter the DEACTIVATE BREAK command, and specify the program location exactly as you did when setting the breakpoint. This causes the debugger to ignore the breakpoint during program execution. However, you can activate it at a later time, for example, when you rerun the program (see Section 1.3.3). A deactivated breakpoint is listed as such in a SHOW BREAK display.
To activate a breakpoint, use the ACTIVATE BREAK command. Activating a breakpoint causes it to take effect during program execution.
The commands DEACTIVATE BREAK/ALL and ACTIVATE BREAK/ALL operate on all breakpoints and are particularly useful when rerunning a program.
To cancel a breakpoint, use the CANCEL BREAK command. A canceled
breakpoint is no longer listed in a SHOW BREAK display.
The SET TRACE command enables you to select locations for tracing the execution of your program (tracepoints), without stopping its execution. After setting a tracepoint, you can start execution with the GO command and then monitor the path of execution, checking for unexpected behavior. By setting a tracepoint on a routine, you can also monitor the number of times it is called.
As with breakpoints, every time a tracepoint is reached, the debugger issues a message and displays the source line. But the program continues executing, and the debugger prompt is not displayed. For example:
This is the only difference between a breakpoint and a tracepoint. When
using the SET TRACE command, you specify address expressions,
qualifiers, and optional clauses exactly as with the SET BREAK command.
The commands SHOW TRACE, ACTIVATE TRACE, DEACTIVATE TRACE, and CANCEL
TRACE operate on tracepoints in a manner similar to the corresponding
commands for breakpoints (see Section 2.3.4).
The SET WATCH command enables you to specify program variables that the debugger monitors as your program executes. This process is called setting watchpoints. If the program modifies the value of a watched variable, the debugger suspends execution and displays information. The debugger monitors watchpoints continuously during program execution. (Note that you can also use the SET WATCH command to monitor arbitrary program locations, not just variables.)
You can set a watchpoint on a variable by specifying the variable's name with the SET WATCH command. For example, the following command sets a watchpoint on the variable TOTAL:
Subsequently, every time the program modifies the value of TOTAL, the watchpoint is triggered.
The following example shows what happens when your program modifies the contents of this watched variable:
In this example, a watchpoint is set on the variable TOTAL and execution is started. When the value of TOTAL changes, execution is paused. The debugger announces the event ("watch of..."), identifying where TOTAL changed (the beginning of line 13) and the associated source line. The debugger then displays the old and new values and announces that execution has been paused at the beginning of the next line (14). Finally, the debugger prompts for another command. When a change in a variable occurs at a point other than the beginning of a source line, the debugger gives the line number plus the byte offset from the beginning of the line.
On Alpha processors, you can set a watchpoint on a nonstatic variable by setting a tracepoint on the defining routine and specifying a DO clause to set the watchpoint whenever execution reaches the tracepoint. Since a nonstatic variable is allocated on the stack or in a register and exists only when its defining routine is active (on the call stack), the variable name is not always meaningful in the way that a static variable name is.
In the following example, a watchpoint is set on the nonstatic variable Y in routine ROUT3. After the tracepoint is triggered, the WPTTRACE message indicates that the nonstatic watchpoint is set, and the watchpoint is triggered when the value of Y changes. For example:
When execution returns to the calling routine, the nonstatic variable is no longer active, so the debugger automatically cancels the watchpoint and issues a message to that effect.
On Alpha processors and Integrity server, the debugger treats all watchpoints as nonstaticwatchpoints.
The commands SHOW WATCH, ACTIVATE WATCH, DEACTIVATE WATCH, and CANCEL
WATCH operate on watchpoints in a manner similar to the corresponding
commands for breakpoints (see Section 2.3.4). However, a nonstatic
watchpoint exists only as long as execution remains within the scope of
the variable being watched.
This section explains how to use the EXAMINE, DEPOSIT, and EVALUATE
commands to display and modify the contents of variables and evaluate
expressions. Before you can examine or deposit into a nonstatic
variable, as defined in Section 2.3.6, its defining routine must be
To display the current value of a variable, use the EXAMINE command. It has the following syntax:
The debugger recognizes the compiler-generated data type of the variable you specify and retrieves and formats the data accordingly. The following examples show some uses of the EXAMINE command.
Examine a string variable:
Examine three integer variables:
Examine a two-dimensional array of real numbers (three per dimension):
Examine element 4 of a one-dimensional array of characters:
Examine a record variable (COBOL example):
Examine a record component (COBOL example):
You can use the EXAMINE command with any kind of address expression
(not just a variable name) to display the contents of a program
location. The debugger associates certain default data types with
untyped locations. If you want the data interpreted and displayed in
some other data format you can override the defaults for typed and
To assign a new value to a variable, use the DEPOSIT command. It has the following syntax:
The DEPOSIT command is like an assignment statement in most programming languages.
In the following examples, the DEPOSIT command assigns new values to different variables. The debugger checks that the value assigned, which can be a language expression, is consistent with the data type and dimensional constraints of the variable.
Deposit a string value (it must be enclosed in quotation marks (") or apostrophes ('):
Deposit an integer expression:
Deposit element 12 of an array of characters (you cannot deposit an entire array aggregate with a single DEPOSIT command, only an element):
Deposit a record component (you cannot deposit an entire record aggregate with a single DEPOSIT command, only a component):
Deposit an out-of-bounds value (X was declared as a positive integer):
As with the EXAMINE command, you can specify any kind of address
expression (not just a variable name) with the DEPOSIT command. You can
override the defaults for typed and untyped locations if you want the
data interpreted in some other data format.
To evaluate a language expression, use the EVALUATE command. It has the following syntax:
The debugger recognizes the operators and expression syntax of the currently set language. In the following example, the value 45 is assigned to the integer variable WIDTH; the EVALUATE command then obtains the sum of the current value of WIDTH and 7:
In the next example, the values TRUE and FALSE are assigned to the Boolean variables WILLING and ABLE, respectively; the EVALUATE command then obtains the logical conjunction of these values:
2.5 Controlling Access to Symbols in Your Program
To have full access to the symbols that are associated with your program (variable names, routine names, source code, line numbers, and so on), you must compile and link the program using the /DEBUG qualifier, as explained in Section 1.2.
Under these conditions, the way in which the debugger handles these symbols is transparent to you in most cases. However, the following two areas might require action:
2.5.1 Setting and Canceling Modules
To facilitate symbol searches, the debugger loads symbol information from the executable image into a run-time symbol table (RST), where that information can be accessed efficiently. Unless symbol information is in the RST, the debugger does not recognize or properly interpret the associated symbols.
Because the RST takes up memory, the debugger loads it dynamically, anticipating what symbols you might want to reference in the course of program execution. The loading process is called module setting, because all symbol information for a given module is loaded into the RST at one time.
Initially, only the module containing the image transfer address is set. Subsequently, whenever execution of the program is interrupted, the debugger sets the module that contains the routine in which execution is paused. This enables you to reference the symbols that should be visible at that location.
If you try to reference a symbol in a module that has not been set, the debugger warns you that the symbol is not in the RST. For example:
You must use the SET MODULE command to set the module containing that symbol explicitly. For example:
The SHOW MODULE command lists the modules of your program and identifies which modules are set.
Dynamic module setting can slow the debugger down as more and more
modules are set. If performance becomes a problem, you can use the
CANCEL MODULE command to reduce the number of set modules, or you can
disable dynamic module setting by entering the SET MODE NODYNAMIC
command (SET MODE DYNAMIC enables dynamic module setting).
Symbol ambiguities can occur when a symbol (for example, a variable name X) is defined in more than one routine or other program unit.
In most cases, the debugger resolves symbol ambiguities automatically. First, it uses the scope and visibility rules of the currently set language. In addition, because the debugger permits you to specify symbols in arbitrary modules (to set breakpoints and so on), the debugger uses the ordering of routine calls on the call stack to resolve symbol ambiguities.
If the debugger cannot resolve a symbol ambiguity, it issues a message. For example:
You can then use a path-name prefix to uniquely specify a declaration of the given symbol. First, use the SHOW SYMBOL command to identify all path names associated with the given symbol (corresponding to all declarations of that symbol) that are currently loaded in the RST. Then use the desired path-name prefix when referencing the symbol. For example:
If you need to refer to a particular declaration of Y repeatedly, use the SET SCOPE command to establish a new default scope for symbol lookup. Then, references to Y without a path-name prefix specify the declaration of Y that is visible in the new scope. For example:
To display the current scope for symbol lookup, use the SHOW SCOPE
command. To restore the default scope, use the CANCEL SCOPE command.
This section walks you through a debugging session with a simple Fortran program that contains a logic error (see Example 2-1). Compiler-assigned line numbers have been added in the example so that you can identify the source lines referenced in the discussion.
The program, called SQUARES, performs the following functions:
When you run SQUARES, it produces the following output, regardless of the number of nonzero elements in the data file:
The error in the program is that variable K, which keeps track of the current index into OUTARR, is not incremented in the loop on lines 9 through 13. The statement K = K + 1 should be inserted just before line 11.
Example 2-2 shows how to start the debugging session and then how to use the debugger to find the error. Comments, keyed to the callouts, follow the example.