[Digital logo]
[HR]

OpenVMS Debugger Manual


Previous | Contents

You might want to enter the SET OUTPUT LOG command in your debugger initialization file (see Section 12.2).

The SHOW LOG command reports whether the debugger is writing to a log file and identifies the current log file. The SHOW OUTPUT command identifies all current output options.

If you are debugging in screen mode, the SET OUTPUT SCREEN_LOG command enables you to log the screen contents as the screen is updated. To use this command, you must already be logging your debugging session---that is, the SET OUTPUT SCREEN_LOG command is valid only after you enter the SET OUTPUT LOG command. Using SET OUTPUT SCREEN_LOG is not desirable for a long debugging session, because storing screen information in this manner results in a large log file. For other techniques on saving screen-mode information, see the SAVE and EXTRACT command descriptions.

To use a log file as a command procedure, first enter the SET OUTPUT VERIFY command so that debugger commands are echoed as they are read.

12.4 Defining Symbols for Commands, Address Expressions, and Values

The DEFINE command enables you to create a symbol for a lengthy or often-repeated command sequence or address expression and to store the value of a language expression in a symbol.

You specify the kind of symbol you want to define by the command qualifier you use with the DEFINE command (/COMMAND, /ADDRESS, or /VALUE). The default qualifier is /ADDRESS. If you plan to enter several DEFINE commands with the same qualifier, you can first use the SET DEFINE command to establish a new default qualifier (for example, SET DEFINE COMMAND makes the DEFINE command behave like DEFINE/COMMAND). The SHOW DEFINE command identifies the default qualifier currently in effect.

Use the SHOW SYMBOL/DEFINED command to identify symbols you have defined with the DEFINE command. Note that the SHOW SYMBOL command without the /DEFINED qualifier identifies only the symbols that are defined in your program, such as the names of routines and variables.

Use the DELETE command to delete symbol definitions created with the DEFINE command.

When defining a symbol within a command procedure, use the /LOCAL qualifier to confine the symbol definition to that command procedure.

12.4.1 Defining Symbols for Commands

Use the DEFINE/COMMAND command to equate one or more command strings to a shorter symbol. The basic syntax is shown in the following example:

DBG> DEFINE/COMMAND SB = "SET BREAK"
DBG> SB PARSER

In the example, the DEFINE/COMMAND command equates the symbol SB to the string SET BREAK (note the use of the quotation marks to delimit the command string). When the command line SB PARSER is executed, the debugger substitutes the string SET BREAK for the symbol SB and then executes the SET BREAK command.

In the following example, the DEFINE/COMMAND command equates the symbol BT to the string consisting of the SHOW BREAK command followed by the SHOW TRACE command (use semicolons to separate multiple command strings):

DBG> DEFINE/COMMAND BT = "SHOW BREAK;SHOW TRACE"

The SHOW SYMBOL/DEFINED command identifies the symbol BT as follows:

DBG> SHOW SYM/DEFINED BT
defined BT 
    bound to: "SHOW BREAK;SHOW TRACE" 
    was defined /command
DBG>

To define complex commands, you might need to use command procedures with parameters (see Section 12.1.2 for information about passing parameters to command procedures). For example:

DBG> DEFINE/COMMAND DUMP =  "@DUMP_PROG2.COM"

12.4.2 Defining Symbols for Address Expressions

Use the DEFINE/ADDRESS command to equate an address expression to a symbol. /ADDRESS is the default qualifier for the DEFINE command, but it is used in the following examples for emphasis.

In the following example, the symbol B1 is equated to the address of line 378; the SET BREAK B1 command then sets a breakpoint on line 378:

DBG> DEFINE/ADDRESS B1 = %LINE 378
DBG> SET BREAK B1

The DEFINE/ADDRESS command is useful when you need to specify a long path name repeatedly to reference the name of a variable or routine that is defined multiple times. In the next example, the symbol UX is equated to the path name SCREEN_IO\UPDATE\X; the abbreviated command line EXAMINE UX can then be used to obtain the value of X in routine UPDATE of module SCREEN_IO:

DBG> DEFINE UX = SCREEN_IO\UPDATE\X
DBG> EXAMINE UX

12.4.3 Defining Symbols for Values

Use the DEFINE/VALUE command to equate the current value of a language expression to a symbol (the current value is the value at the time the
DEFINE/VALUE command was entered).

The following example shows how you can use the DEFINE/VALUE command to count the number of calls to a routine:

 
DBG> DEFINE/VALUE COUNT = 0
DBG> SET TRACE/SILENT ROUT DO (DEFINE/VALUE COUNT = COUNT + 1)
DBG> GO
   .
   .
   .
DBG> EVALUATE COUNT
14
DBG>

In the example, the first DEFINE/VALUE command initializes the value of the symbol COUNT to 0. The SET TRACE command sets a silent tracepoint on routine ROUT and (through the DO clause) increments the value of COUNT by 1 every time ROUT is called. After execution is resumed and eventually suspended, the EVALUATE command obtains the current value of COUNT (the number of times that ROUT was called).

12.5 Assigning Commands to Function Keys

To facilitate entering commonly used commands, the function keys on the keypad have predefined debugger functions that are established when you start the debugger. These predefined functions are identified in Appendix A. You can modify the functions of the keypad keys to suit your individual needs. If you have a VT200- or VT300-series terminal or a workstation, you can also bind commands to the additional function keys on the LK201 keyboard.

The debugger commands DEFINE/KEY, SHOW KEY, and DELETE/KEY enable you to assign, identify, and delete key definitions, respectively. Before you can use this feature, keypad mode must be enabled with the SET MODE KEYPAD command (keypad mode is enabled by default). Keypad mode also enables you to use the predefined functions of the keypad keys.

To use the keypad keys to enter numbers rather than debugger commands, enter the SET MODE NOKEYPAD command.

12.5.1 Basic Conventions

The debugger DEFINE/KEY command, which is similar to the DCL command DEFINE/KEY, enables you to assign a string to a function key. In the following example, the DEFINE/KEY command defines KP7 (keypad key 7) to enter and execute the SHOW MODULE * command:

DBG> DEFINE/KEY/TERMINATE KP7 "SHOW MODULE *"
%DEBUG-I-DEFKEY, DEFAULT key KP7 has been defined
DBG>

You must use a valid key name (such as KP7) with the commands DEFINE/KEY, SHOW KEY, and DELETE/KEY. See the DEFINE/KEY command for the valid key names that you can use with these commands for VT52 and VT100-series terminals and for LK201 keyboards.

In the previous example, the /TERMINATE qualifier indicates that pressing KP7 executes the command. You do not have to press Return after pressing KP7.

You can assign any number of definitions to the same function key as long as each definition is associated with a different state. The predefined states (DEFAULT, GOLD, BLUE, and so on) are identified in Appendix A. In the preceding example, the informational message indicates that KP7 has been defined for the DEFAULT state (which is the default key state).

You can enter key definitions in a debugger initialization file (see Section 12.2) so that these definitions are available whenever you start the debugger.

To display a key definition in the current state, enter the SHOW KEY command. For example:

DBG> SHOW KEY KP7
DEFAULT keypad definitions: 
  KP7 = "SHOW MODULE *" (echo,terminate,nolock)
DBG>

To display a key definition in a state other than the current state, specify that state with the /STATE qualifier when entering the SHOW KEY command. To see all key definitions in the current state, enter the SHOW KEY/ALL command.

To delete a key definition, use the DELETE/KEY command. To delete a key definition in a state other than the current state, specify that state with the /STATE qualifier. For example:

DBG> DELETE/KEY/STATE=GOLD KP7
%DEBUG-I-DELKEY, GOLD key KP7 has been deleted
DBG>

12.5.2 Advanced Techniques

This section shows more advanced techniques for defining keys, particularly techniques related to the use of state keys.

The following command line assigns the unterminated command string SET BREAK %LINE to KP9, for the BLUE state:

DBG> DEFINE/KEY/IF_STATE=BLUE KP9 "SET BREAK %LINE"

The predefined DEFAULT key state is established by default. The predefined BLUE key state is established by pressing the PF4 key. Enter the command line assigned in the preceding example (SET BREAK %LINE ...) by pressing PF4, pressing KP9, entering a line number, and then pressing the Return key to terminate and process the command line.

The SET KEY command enables you to change the default state for key definitions. For example, after entering the SET KEY/STATE=BLUE command, you do not need to press PF4 to enter the command line in the previous example. Also, the SHOW KEY command will show key definitions in the BLUE state, by default, and the DELETE/KEY command will delete key definitions in the BLUE state by default.

You can create additional key states. For example:

DBG> SET KEY/STATE=DEFAULT
DBG> DEFINE/KEY/SET_STATE=RED/LOCK_STATE F12 ""

In this example, the SET KEY command establishes DEFAULT as the current state. The DEFINE/KEY command makes F12 (LK201 keyboard) a state key. As a result, pressing F12 while in the DEFAULT state causes the current state to become RED. The key definition is not terminated and has no other effect (a null string is assigned to F12). After pressing F12, you can enter RED commands by pressing keys that have definitions associated with the RED state.

12.6 Using Control Structures to Enter Commands

The FOR, IF, REPEAT, and WHILE commands enable you to create looping and conditional constructs for entering debugger commands. The associated command EXITLOOP is used to exit a FOR, REPEAT, or WHILE loop. The following sections describe these commands.

See Section 4.1.6 and Section 13.3.2.2 for information about evaluating language expressions.

12.6.1 FOR Command

The FOR command executes a sequence of commands while incrementing a variable a specified number of times. It has the following syntax:

FOR name=expression1 TO expression2 [BY expression3] DO(command[; ...]) 

For example, the following command line sets up a loop that initializes the first 10 elements of an array to 0:

DBG> FOR I = 1 TO 10 DO (DEPOSIT A(I) = 0)

12.6.2 IF Command

The IF command executes a sequence of commands if a language expression (Boolean expression) is evaluated as true. It has the following syntax:

IF boolean-expression THEN (command[; ...]) [ELSE (command[;...])] 

The following Fortran example sets up a condition that issues the command EXAMINE X2 if X1 is not equal to - 9.9, and issues the command EXAMINE Y1 otherwise:

DBG> IF X1 .NE. -9.9 THEN (EXAMINE X2) ELSE (EXAMINE Y1)

The following Pascal example combines a FOR loop and a condition test. The STEP command is issued if X1 is not equal to - 9.9. The test is made four times:

DBG> FOR COUNT = 1 TO 4 DO (IF X1 <> -9.9 THEN (STEP))

12.6.3 REPEAT Command

The REPEAT command executes a sequence of commands a specified number of times. It has the following syntax:

REPEAT language-expression DO (command[; ...]) 

For example, the following command line sets up a loop that issues a sequence of two commands (EXAMINE Y then STEP) 10 times:

DBG> REPEAT 10 DO (EXAMINE Y; STEP)

12.6.4 WHILE Command

The WHILE command executes a sequence of commands while the language expression (Boolean expression) you have specified evaluates as true. It has the following syntax:

WHILE boolean-expression DO (command[; ...]) 

The following Pascal example sets up a loop that repetitively tests X1 and X2 and issues the two commands EXAMINE X2 and STEP if X2 is less than X1:

DBG> WHILE X2 < X1 DO (EX X2;STEP)

12.6.5 EXITLOOP Command

The EXITLOOP command exits one or more enclosing FOR, REPEAT, or WHILE loops. It has the following syntax:

EXITLOOP [integer] 

The integer n specifies the number of nested loops to exit from.

The following Pascal example sets up an endless loop that issues a STEP command with each iteration. After each step, the value of X is tested. If X is greater than 3, the EXITLOOP command terminates the loop.

DBG> WHILE TRUE DO (STEP; IF X > 3 THEN EXITLOOP)

12.7 Calling Routines Independently of Program Execution

The CALL command enables you to execute a routine independently of the normal execution of your program. It is one of the four debugger commands that you can use to execute your program (the others are GO, STEP, and EXIT).

The CALL command executes a routine whether or not your program actually includes a call to that routine, as long as the routine was linked with your program. Thus, you can use the CALL command to execute routines for any purpose (for example, to debug a routine out of the context of program execution, call a run-time library procedure, call a routine that dumps debugging information, and so on).

You can debug unrelated routines by linking them with a dummy main program that has a transfer address, and then using the CALL command to execute them.

The following example shows how you can use the CALL command to display some process statistics without having to include the necessary code in your program. The example consists of calls to run-time library routines that initialize a timer (LIB$INIT_TIMER) and display the elapsed time and various statistics (LIB$SHOW_TIMER). (Note that the presence of the debugger affects the timings and counts.)

DBG> SET MODULE SHARE$LIBRTL   (1)
DBG> CALL LIB$INIT_TIMER   (2)
value returned is 1   (3)
DBG> [ enter various debugger commands ]
   .
   .
   .
DBG> CALL LIB$SHOW_TIMER   (4)
 ELAPSED: 0 00:00:21.65  CPU: 0:14:00.21  BUFIO: 16  DIRIO: 0  FAULTS: 3 
value returned is 1
DBG>

The comments that follow refer to the callouts in the previous example:

  1. The routines LIB$INIT_TIMER and LIB$SHOW_TIMER are in the shareable image LIBRTL. This image must be set by setting its module, because only its universal symbols are accessible during a debugging session (see Section 5.4.2.3).
  2. This CALL command executes the routine LIB$INIT_TIMER.
  3. The value returned message indicates the value returned in register R0 after the CALL command has been executed.
    By convention, after a called routine has executed, register R0 contains the function return value (if the routine is a function) or the procedure completion status (if the routine is a procedure that returns a status value). If a called procedure does not return a status value or function value, the value in R0 might be meaningless, and the value returned message can be ignored.
  4. This CALL command executes the routine LIB$SHOW_TIMER.

The following example shows how to call LIB$SHOW_VM (also in LIBRTL) to display memory statistics. Again, note that the presence of the debugger affects the counts.

DBG> SET MODULE SHARE$LIBRTL
DBG> CALL LIB$SHOW_VM
 1785 calls to LIB$GET_VM, 284 calls to LIB$FREE_VM, 
 122216 bytes still allocated value returned is 1
DBG>

You can pass parameters to routines with the CALL command. See the CALL command description for details and examples.


Chapter 13
Debugging Special Cases

This chapter presents debugging techniques for special cases that are not covered elsewhere in this manual:

13.1 Debugging Optimized Code

By default, many compilers optimize the code they produce so that the program executes faster. With optimization, invariant expressions are removed from DO loops so that they are evaluated only once at run time, some memory locations might be allocated to different variables at different points in the program, and some variables might be eliminated so that you no longer have access to them while debugging.

The net result is that the code that is executing as you debug might not match the source code displayed in a screen-mode source display (see Section 7.4.1) or in a source listing file.

To avoid the problems of debugging optimized code, many compilers allow you to specify the /NOOPTIMIZE (or equivalent) command qualifier at compile time. Specifying this qualifier inhibits most compiler optimization and thereby reduces discrepancies between the source code and executable code caused by optimization.

If this option is not available to you, or if you have a definite need to debug optimized code, read this section. It describes the techniques for debugging optimized code and gives some typical examples of optimized code to show the potential causes of confusion. It also describes some features you can use to reduce the confusion inherent in debugging optimized code.

In order to take advantage of the features that improve the ability to debug optimized code, you need an up-to-date version of your language compiler. For definitive information about the necessary version of your compiler, please see your compiler release notes or other compiler documentation.

Note that about one-third more disk space is needed for debugging optimized code, to accommodate the increased image size.

When debugging optimized code, use a screen-mode instruction display, such as the predefined display INST, to show the decoded instruction stream of your program (see Section 7.4.4). An instruction display shows the exact code that is executing.

In screen mode, pressing KP7 places the SRC and INST displays side by side for easy comparison. Alternatively, you can inspect a compiler-generated machine-code listing.

In addition, to execute the program at the instruction level and examine instructions, use the techniques described in Section 4.3.

Using these methods, you should be able to determine what is happening at the executable code level and be able to resolve the discrepancy between source display and program behavior.

13.1.1 Eliminated Variables

A compiler might optimize code by eliminating variables, either permanently or temporarily at various points during execution. For example, if you try to examine a variable X that no longer is accessible because of optimization, the debugger might display one of the following messages:

%DEBUG-W-UNALLOCATED, entity X was not allocated in memory 
                      (was optimized away) 
 
%DEBUG-W-NOVALATPC, entity X does not have a value at the 
                    current PC 

The following Pascal example shows how this could happen:

PROGRAM DOC(OUTPUT); 
   VAR 
      X,Y: INTEGER; 
   BEGIN 
      X := 5; 
      Y := 2; 
      WRITELN(X*Y); 
   END. 

If you compile this program with the /NOOPTIMIZE (or equivalent) qualifier, you obtain the following (normal) behavior when debugging:

$ PASCAL/DEBUG/NOOPTIMIZE DOC
$ LINK/DEBUG DOC
$ DEBUG/KEEP
   .
   .
   .
DBG> RUN DOC
   .
   .
   .
DBG> STEP
stepped to DOC\%LINE 5 
     5:         X := 5;
DBG> STEP
stepped to DOC\%LINE 6 
     6:         Y := 2;
DBG> STEP
stepped to DOC\%LINE 7 
     7:         WRITELN(X*Y);
DBG> EXAMINE X,Y
DOC\X:  5 
DOC\Y:  2
DBG>

If you compile the program with the /OPTIMIZE (or equivalent) qualifier, because the values of X and Y are not changed after the initial assignment, the compiler calculates X*Y, stores that value (10), and does not allocate storage for X or Y. Therefore, after you start debugging, a STEP command takes you directly to line 7 rather than line 5. Moreover, you cannot examine X or Y:

$ PASCAL/DEBUG/OPTIMIZE DOC
$ LINK/DEBUG DOC
$ DEBUG/KEEP
   .
   .
   .
DBG> RUN DOC
   .
   .
   .
DBG> EXAMINE X,Y
%DEBUG-W-UNALLOCATED, entity X was not allocated in memory 
                      (was optimized away)
DBG> STEP
stepped to DOC\%LINE 7 
     7:         WRITELN(X*Y);
DBG>

On VAX processors, to see what values are being used in your optimized program, use the EXAMINE/OPERAND .%PC command to display the machine code at the current PC value, including the values and symbolization of all of the operands. For example, the following lines show the optimized code when the PC value is at the WRITELN statement:

DBG> STEP
stepped to DOC\%LINE 7 
     7:         WRITELN(X*Y);
DBG> EXAMINE/OPERAND .%PC
DOC\%LINE 7:    PUSHL   S^#10
DBG>

In contrast, the following lines show the unoptimized code at the WRITELN statement:

DBG> STEP
stepped to DOC\%LINE 7 
     7:         WRITELN(X*Y);
DBG> EXAMINE/OPERAND .%PC
DOC\%LINE 7:    MOVL    S^#10,B^-4(FP) 
     B^-4(FP)   2146279292 contains 62914576
DBG> 
 

13.1.2 Changes in Coding Order

Several methods of optimizing consist of performing operations in a sequence different from the sequence specified in the source code. Sometimes code is eliminated altogether.

As a result, the source code displayed by the debugger does not correspond exactly to the actual code being executed.

The following example depicts a segment of source code from a Fortran program as it might appear on a compiler listing or in a screen-mode source display. This code segment sets the first ten elements of array A to the value 1/X.

Line          Source Code 
----          ----------- 
  5            DO 100 I=1,10 
  6            A(I) = 1/X 
  7        100 CONTINUE 

Optimization may produce the following scenario: As the compiler processes the source program, it determines that the reciprocal of X need only be computed once, not 10 times as the source code specifies, because the value of X never changes in the DO loop. The compiler thus may generate optimized code equivalent to the following code segment:

Line          Optimized Code Equivalent 
----          ------------------------- 
  5            TEMP = 1/X 
               DO 100 I=1,10 
  6            A(I) = TEMP 
  7        100 CONTINUE 

Depending on the compiler implementation, the moved code may be associated with the first line of the loop (common on VAX systems) or may retain its original line number (common on Alpha systems).

If a discrepancy occurs, it is not obvious from looking at the displayed source line. Furthermore, if the computation of 1/X were to fail because X is 0, it would appear from inspecting the source display that a division by 0 had occurred on a source line that contains no division at all.

This kind of apparent mismatch between source code and executable code should be expected from time to time when you debug optimized programs. It can be caused not only by code motions out of loops, as in the previous example, but by a number of other optimization methods as well.

13.1.3 Semantic Stepping (Alpha Only)

Semantic stepping (available only on Alpha systems) makes stepping through optimized code less confusing. The semantic-stepping mode complements the traditional step-by-line and step-by-instruction modes. There are two commands for semantic stepping: SET STEP SEMANTIC_EVENT and STEP/SEMANTIC_EVENT.

Semantic Events

One problem of stepping through optimized code is that the apparent source program location "bounces" back and forth with the same line often appearing again and again. Indeed, sometimes the forward progress in STEP LINE mode averages barely more than one instruction per STEP command.

This problem is addressed through annotating instructions that are semantic events. Semantic events are important for two reasons:

A semantic event is one of the following:

It is important to understand that not every assignment, transfer of control, or call is necessarily a semantic event. The major exceptions are as follows:

SET STEP SEMANTIC_EVENT Command

The SET STEP SEMANTIC_EVENT command establishes the default stepping mode as semantic.

STEP/SEMANTIC_EVENT Command

STEP/SEMANTIC_EVENT, or simply STEP when semantic mode is in effect, causes a breakpoint to be set at the next semantic event, whether an assignment, a transfer of control, or a call. Execution proceeds to that next event. Parts of any number of different lines/statements may be executed along the way without interfering with progress. When the semantic event is reached (that is, when the instruction associated with that event is reached but not yet executed), execution is suspended (similar to reaching the next line when STEP/LINE is used).

Example of Semantic Stepping


Previous | Next | Contents | [Home] | [Comments] | [Ordering info] | [Help]

[HR]

  4538P020.HTM
  OSSG Documentation
  22-NOV-1996 13:02:01.11

Copyright © Digital Equipment Corporation 1996. All Rights Reserved.

Legal