Previous | Contents | Index |
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:
DBG> SET BREAK COUNT DBG> GO . . . break at routine PROG2\COUNT 54: procedure COUNT(X,Y:INTEGER); DBG> |
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.
DBG> SET BREAK %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:
DBG> SET BREAK SCREEN_IO\%LINE 58 |
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:
DBG> SET BREAK/LINE DBG> SET BREAK/CALL |
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.
2.3.5 Tracing Program Execution with Tracepoints
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:
DBG> SET TRACE COUNT DBG> GO trace at routine PROG2\COUNT 54: procedure COUNT(X,Y:INTEGER); . . . |
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).
2.3.6 Monitoring Changes in Variables with Watchpoints
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:
DBG> SET WATCH TOTAL |
Subsequently, every time the program modifies the value of TOTAL, the watchpoint is triggered.
The technique you use to set watchpoints depends on your system (Alpha or Integrity servers) and the type of variable, static or nonstatic. On Alpha systems, for example, a static variable is associated with the same memory address throughout program execution. |
The following example shows what happens when your program modifies the contents of this watched variable:
DBG> SET WATCH TOTAL DBG> GO . . . watch of SCREEN_IO\TOTAL at SCREEN_IO\%LINE 13 13: TOTAL = TOTAL + 1; old value: 16 new value: 17 break at SCREEN_IO\%LINE 14 14: POP(TOTAL); DBG> |
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:
DBG> SET TRACE/NOSOURCE ROUT3 DO (SET WATCH Y) DBG> GO . . . trace at routine MOD4\ROUT3 %DEBUG-I-WPTTRACE, nonstatic watchpoint, tracing every instruction . . . watch of MOD4\ROUT3\Y at MOD4\ROUT3\%LINE 16 16: Y := 4 old value: 3 new value: 4 break at MOD4\ROUT3\%LINE 17 17: SWAP(X,Y); DBG> |
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.
2.4 Examining and Manipulating Program Data
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
active.
2.4.1 Displaying the Value of a Variable
To display the current value of a variable, use the EXAMINE command. It has the following syntax:
EXAMINE address-expression |
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:
DBG> EXAMINE EMPLOYEE_NAME PAYROLL\EMPLOYEE_NAME: "Peter C. Lombardi" DBG> |
Examine three integer variables:
DBG> EXAMINE WIDTH, LENGTH, AREA SIZE\WIDTH: 4 SIZE\LENGTH: 7 SIZE\AREA: 28 DBG> |
Examine a two-dimensional array of real numbers (three per dimension):
DBG> EXAMINE REAL_ARRAY PROG2\REAL_ARRAY (1,1): 27.01000 (1,2): 31.00000 (1,3): 12.48000 (2,1): 15.08000 (2,2): 22.30000 (2,3): 18.73000 DBG> |
Examine element 4 of a one-dimensional array of characters:
DBG> EXAMINE CHAR_ARRAY(4) PROG2\CHAR_ARRAY(4): 'm' DBG> |
Examine a record variable (COBOL example):
DBG> EXAMINE PART INVENTORY\PART: ITEM: "WF-1247" PRICE: 49.95 IN_STOCK: 24 DBG> |
Examine a record component (COBOL example):
DBG> EXAMINE IN_STOCK OF PART INVENTORY\IN-STOCK of PART: IN_STOCK: 24 DBG> |
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
untyped locations.
2.4.2 Assigning a Value to a Variable
To assign a new value to a variable, use the DEPOSIT command. It has the following syntax:
DEPOSIT address-expression = language-expression |
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 ('):
DBG> DEPOSIT PART_NUMBER = "WG-7619.3-84" |
Deposit an integer expression:
DBG> DEPOSIT WIDTH = CURRENT_WIDTH + 10 |
Deposit element 12 of an array of characters (you cannot deposit an entire array aggregate with a single DEPOSIT command, only an element):
DBG> DEPOSIT C_ARRAY(12) := 'K' |
Deposit a record component (you cannot deposit an entire record aggregate with a single DEPOSIT command, only a component):
DBG> DEPOSIT EMPLOYEE.ZIPCODE = 02172 |
Deposit an out-of-bounds value (X was declared as a positive integer):
DBG> DEPOSIT X = -14 %DEBUG-I-IVALOUTBNDS, value assigned is out of bounds at or near DEPOSIT |
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.
2.4.3 Evaluating Language Expressions
To evaluate a language expression, use the EVALUATE command. It has the following syntax:
EVALUATE language-expression |
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:
DBG> DEPOSIT WIDTH := 45 DBG> EVALUATE WIDTH + 7 52 DBG> |
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:
DBG> DEPOSIT WILLING := TRUE DBG> DEPOSIT ABLE := FALSE DBG> EVALUATE WILLING AND ABLE False DBG> |
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:
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:
DBG> EXAMINE K %DEBUG-W-NOSYMBOL, symbol 'K' is not in symbol table DBG> |
You must use the SET MODULE command to set the module containing that symbol explicitly. For example:
DBG> SET MODULE MOD3 DBG> EXAMINE K MOD3\ROUT2\K: 26 DBG> |
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).
2.5.2 Resolving Symbol Ambiguities
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:
DBG> EXAMINE Y %DEBUG-W-NOUNIQUE, symbol 'Y' is not unique DBG> |
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:
DBG> SHOW SYMBOL Y data MOD7\ROUT3\BLOCK1\Y data MOD4\ROUT2\Y DBG> EXAMINE MOD4\ROUT2\Y MOD4\ROUT2\Y: 12 DBG> |
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:
DBG> SET SCOPE MOD4\ROUT2 DBG> EXAMINE Y MOD4\ROUT2\Y: 12 DBG> |
To display the current scope for symbol lookup, use the SHOW SCOPE
command. To restore the default scope, use the CANCEL SCOPE command.
2.6 Sample Debugging Session
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:
Example 2-1 Sample Program SQUARES |
---|
1: INTEGER INARR(20), OUTARR(20) 2: C 3: C ---Read the input array from the data file. 4: OPEN(UNIT=8, FILE='DATAFILE.DAT', STATUS='OLD') 5: READ(8,*) N, (INARR(I), I=1,N) 6: C 7: C ---Square all nonzero elements and store in OUTARR. 8: K = 0 9: DO 10 I = 1, N 10: IF(INARR(I) .NE. 0) THEN 11: OUTARR(K) = INARR(I)**2 12: ENDIF 13: 10 CONTINUE 14: C 15: C ---Print the squared output values. Then stop. 16: PRINT 20, K 17: 20 FORMAT(' Number of nonzero elements is',I4) 18: DO 40 I = 1, K 19: PRINT 30, I, OUTARR(I) 20: 30 FORMAT(' Element',I4,' has value',I6) 21: 40 CONTINUE 22: END |
When you run SQUARES, it produces the following output, regardless of the number of nonzero elements in the data file:
$ RUN SQUARES Number of nonzero elements is 0 |
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.
Example 2-2 Sample Debugging Session Using Program SQUARES |
---|
$ FORTRAN/DEBUG/NOOPTIMIZE SQUARES (1) $ LINK/DEBUG SQUARES (2) $ DEBUG/KEEP (3) Debugger Banner and Version Number DBG> RUN SQUARES (4) Language: FORTRAN, Module: SQUARES$MAIN DBG> STEP 4 (5) stepped to SQUARES$MAIN\%LINE 9 9: DO 10 I = 1, N DBG> EXAMINE N,K (6) SQUARES$MAIN\N: 9 SQUARES$MAIN\K: 0 DBG> STEP 2 (7) stepped to SQUARES$MAIN\%LINE 11 11: OUTARR(K) = INARR(I)**2 DBG> EXAMINE I,K (8) SQUARES$MAIN\I: 1 SQUARES$MAIN\K: 0 DBG> DEPOSIT K = 1 (9) DBG> SET TRACE/SILENT %LINE 11 DO (DEPOSIT K = K + 1) (10) DBG> GO (11) Number of nonzero elements is 4 Element 1 has value 16 Element 2 has value 36 Element 3 has value 9 Element 4 has value 49 'Normal successful completion' DBG> SPAWN (12) $ EDIT SQUARES.FOR (13) . . . 10: IF(INARR(I) .NE. 0) THEN 11: K = K + 1 12: OUTARR(K) = INARR(I)**2 13: ENDIF . . . $ FORTRAN/DEBUG/NOOPTIMIZE SQUARES (14) $ LINK/DEBUG SQUARES $ LOGOUT (15) DBG> RUN SQUARES (16) Language: FORTRAN, Module: SQUARES$MAIN DBG> SET BREAK %LINE 12 DO (EXAMINE I,K) (17) DBG> GO (18) SQUARES$MAIN\I: 1 SQUARES$MAIN\K: 1 DBG> GO SQUARES$MAIN\I: 2 SQUARES$MAIN\K: 2 DBG> GO SQUARES$MAIN\I: 4 SQUARES$MAIN\K: 3 DBG> EXIT (19) $ |
The following comments apply to the callouts in Example 2-2. Example 2-1 shows the program that is being debugged.
Previous | Next | Contents | Index |