OpenVMS Debugger Manual


Previous Contents Index

14.2 Debugging Screen-Oriented Programs

The debugger uses the terminal screen for input and output (I/O) during a debugging session. If you use a single terminal to debug a screen-oriented program that uses most or all of the screen, debugger I/O can overwrite, or can be overwritten by, program I/O.

Using one terminal for both program I/O and debugger I/O is even more complicated if you are debugging in screen mode and your screen-oriented program calls any Run-Time Library (RTL) Screen Management (SMG$) routines. This is because the debugger's screen mode also calls SMG routines. In such cases, the debugger and your program share the same SMG pasteboard, which causes further interference.

To avoid these problems when debugging a screen-oriented program, use one of the following techniques to separate debugger I/O from program I/O:

Assume that TTD1: is your current terminal from which you plan to start the debugger. You want to display debugger I/O on terminal TTD2: so that TTD1: is devoted exclusively to program I/O.

Follow these steps:

  1. Provide the necessary protection to TTD2: so that you can allocate that terminal from TTD1: (see Section 14.2.1).
    The remaining steps are all performed from TTD1:.
  2. Allocate TTD2:. This provides your process on TTD1: with exclusive access to TTD2: as follows:


    $ ALLOCATE TTD2:
    

  3. Assign the debugger logical names DBG$INPUT and DBG$OUTPUT to TTD2: as follows:


    $ DEFINE DBG$INPUT TTD2:
    $ DEFINE DBG$OUTPUT TTD2:
    

    DBG$INPUT and DBG$OUTPUT specify the debugger input device and output device, respectively. By default, these logical names are equated to SYS$INPUT and SYS$OUTPUT, respectively. Assigning DBG$INPUT and DBG$OUTPUT to TTD2: enables you to display debugger commands and debugger output on TTD2:.

  4. Make sure that the terminal type is known to the system. Enter the following command:


    $ SHOW DEVICE/FULL TTD2:
    

    If the device type is unknown, your system manager (or a user with LOG_IO or PHY_IO privilege) must make it known to the system as shown in the following example. In the example, the terminal is assumed to be a VT200:


    $ SET TERMINAL/PERMANENT/DEVICE=VT200 TTD2:
    

  5. Run the program to be debugged:


    $ DEBUG/KEEP
       .
       .
       .
    DBG> RUN prog-name
    

    You can now observe debugger I/O on TTD2:

  6. When finished with the debugging session, deallocate TTD2: as follows (or log out):


    $ DEALLOCATE TTD2:
    

14.2.1 Setting the Protection to Allocate a Terminal

On a properly secured system, terminals are protected so that you cannot allocate a terminal from another terminal.

To set the necessary protection, your system manager (or a user with the privileges indicated) should follow the steps shown in the following example.

In the example, TTD1: is your current terminal (from which you plan to start the debugger), and TTD2: is the terminal to be allocated so that it can display debugger I/O.

  1. If both TTD1: and TTD2: are hardwired to the system, go to Step 4.
    If TTD1: and TTD2: are connected to the system over a LAT (local area transport), go to Step 2.
  2. Log in to TTD2:.
  3. Enter these commands (you need LOG_IO or PHY_IO privilege):


    $ SET PROCESS/PRIV=LOG_IO
    $ SET TERMINAL/NOHANG/PERMANENT
    $ LOGOUT/NOHANG
    

  4. Enter one of the following commands (you need OPER privilege):


    $ SET ACL/OBJECT_TYPE=DEVICE/ACL=(IDENT=[PROJ,JONES],ACCESS=READ+WRITE) TTD2:   (1)
    $ SET PROTECTION=WORLD:RW/DEVICE TTD2:   (2)
    

    1. The SET ACL command line is preferred because it uses an access control list (ACL). In the example, access is restricted to user identification code (UIC) [PROJ,JONES].
    2. The SET PROTECTION command line provides world read/write access, which allows any user to allocate and perform I/O to TTD2:.

14.3 Debugging Multilanguage Programs

The debugger enables you to debug modules whose source code is written in different languages within the same debugging session. This section highlights some language-specific behavior that you should be aware of to minimize possible confusion.

When debugging in any language, be sure to consult:

14.3.1 Controlling the Current Debugger Language

When you bring a program under debugger control, the debugger sets the current language to that in which the module containing the main program (usually the routine containing the image transfer address) is written. The current language is identified at that point. For example:


$ DEBUG/KEEP
           Debugger Banner and Version Number
DBG> RUN prog-name
Language: PASCAL, Module: FORMS
DBG>

The current language setting determines how the debugger parses and interprets the names, operators, and expressions you specify in debugger commands, including things like the typing of variables, array and record syntax, the default radix for integer data, case sensitivity, and so on. The language setting also determines how the debugger displays data associated with your program.

Many programs include modules that are written in languages other than that of the main program. To minimize confusion, by default the debugger language remains set to the language of the main program throughout a debugging session, even if execution is paused within a module written in another language.

To take full advantage of symbolic debugging with such modules, use the SET LANGUAGE command to set the debugging context to that of another language. For example, the following command causes the debugger to interpret any symbols, expressions, and so on according to the rules of the COBOL language:


DBG> SET LANGUAGE COBOL

On Alpha processors, the SET LANGUAGE command takes the following keywords:
Ada BASIC BLISS C
C++ COBOL Fortran MACRO-32 1
MACRO-64 Pascal PL/I  


1Note that MACRO-32 must be compiled with the AMACRO compiler.

On Integrity server processors, the SET LANGUAGE command takes the following keywords:
Assembler (IAS) BASIC BLISS C
C++ COBOL Fortran MACRO-32 1
IMACRO PASCAL    
Assembler (IAS) BASIC BLISS C
C++ COBOL Fortran MACRO-32 1
IMACRO PASCAL    


1Note that MACRO-32 must be compiled with the AMACRO compiler.
1Note that MACRO-32 must be compiled with the AMACRO compiler.

In addition, when debugging a program that is written in an unsupported language, you can specify the SET LANGUAGE UNKNOWN command. To maximize the usability of the debugger with unsupported languages, the SET LANGUAGE UNKNOWN command causes the debugger to accept a large set of data formats and operators, including some that might be specific to only a few supported languages. The operators and constructs that are recognized when the language is set to UNKNOWN are identified in the debugger's online help (type HELP Language).

14.3.2 Specific Differences Among Languages

This section lists some of the differences you should keep in mind when debugging in various languages. Included are differences that are affected by the SET LANGUAGE command and other differences (for example, language-specific initialization code and predefined breakpoints).

This section is not intended to be complete. See the debugger's online help (type HELP Language) and your language documentation for complete details.

14.3.2.1 Default Radix

The default radix for entering and displaying integer data is decimal for most languages.

On Alpha processors, the exceptions are BLISS, MACRO--32, and MACRO--64, which have a hexadecimal default radix.

Use the SET RADIX command to establish a new default radix.

14.3.2.2 Evaluating Language Expressions

Several debugger commands and constructs evaluate language expressions:

When processing these commands, the debugger evaluates language expressions in the syntax of the current language and in the current radix as discussed in Section 4.1.6. At each execution (not when you enter the command), the debugger checks the syntax of any expressions in WHEN or DO clauses, and then evaluates them.

Note that operators vary widely among different languages. For example, the following two commands evaluate equivalent expressions in Pascal and Fortran, respectively:


DBG> SET WATCH X WHEN (Y < 5)       ! Pascal 
DBG> SET WATCH X WHEN (Y .LT. 5)    ! FORTRAN 

Assume that the language is set to Pascal and you have entered the first (Pascal) command. You now step into a Fortran routine, set the language to Fortran, and resume execution. While the language is set to Fortran, the debugger is not able to evaluate the expression (Y < 5). As a result, it sets an unconditional watchpoint and, when the watchpoint is triggered, returns a syntax error for the < operator.

This type of discrepancy can also occur if you use commands that evaluate language expressions in debugger command procedures and initialization files.

When the language is set to BLISS, the debugger processes language expressions that contain variable names (or other address expressions) differently than when it is set to another language. See Section 4.1.6 for details.

14.3.2.3 Arrays and Records

The syntax for denoting array elements and record components (if applicable) varies among languages.

For example, some languages use brackets ([]), and others use parentheses (( )), to delimit array elements.

Some languages have zero-based arrays. Some languages have one-based arrays, as in the following example:


DBG> EXAMINE INTEGER_ARRAY
PROG2\INTEGER_ARRAY 
   (1,1):       27 
   (1,2):       31 
   (1,3):       12 
   (2,1):       15 
   (2,2):       22 
   (2,3):       18
DBG>

For some languages (like Pascal and Ada) the specific array declaration determines how the array is based.

14.3.2.4 Case Sensitivity

Names and language expressions are case sensitive in C. You must specify them exactly as they appear in the source code. For example, the following two commands are not equivalent when the language is set to C:


DBG> SET BREAK SCREEN_IO\%LINE 10
DBG> SET BREAK screen_io\%LINE 10

14.3.2.5 Initialization Code

Many programs issue a NOTATMAIN message when a program is brought under debugger control. For example:


$ DEBUG/KEEP
           Debugger Banner and Version Number
DBG> RUN prog-name
Language: ADA, Module: MONITOR 
Type GO to reach main program
DBG>

The NOTATMAIN message indicates that execution is paused before the beginning of the main program. This enables you to execute and check some initialization code under debugger control.

The initialization code is created by the compiler and is placed in a special PSECT named LIB$INITIALIZE. For example, in the case of an Ada package, the initialization code belongs to the package body (which might contain statements to initialize variables, and so on). In the case of a Fortran program, the initialization code declares the handler that is needed if you specify the /CHECK=UNDERFLOW or /CHECK=ALL qualifier.

The NOTATMAIN message indicates that, if you do not want to debug the initialization code, you can execute immediately to the beginning of the main program by entering a GO command. You are then at the same point as when you start debugging any other program. Entering the GO command again starts program execution.

14.3.2.6 Predefined Breakpoints

If your program is a tasking program, two breakpoints that are associated with tasking exception events are automatically established when the program is brought under debugger control. These breakpoints are not affected by a SET LANGUAGE command. They are established automatically during debugger initialization when appropriate run-time libraries are present.

To identify these predefined breakpoints, enter the SHOW BREAK command. For example:


DBG> SHOW BREAK
Predefined breakpoint on ADA event "EXCEPTION_TERMINATED" for any value 
Predefined breakpoint on ADA event "DEPENDENTS_EXCEPTION" for any value
DBG>

14.4 Recovering from Stack Corruption

The debugger allocates a certain amount of memory at startup and shares the stack with the user's program. If a user process exception results in exhaustion of resources or corruption of the stack, the debugger may be incapable of regaining control, and the debug session may terminate.

Be aware of this potential behavior after the occurrence of stack corruption messages or warnings about continuing from a severe error. In either case, the integrity of the debug session cannot be guaranteed.

You should try one of the following measures:

14.5 Debugging Exceptions and Condition Handlers

A condition handler is a procedure that the operating system executes when an exception occurs.

Exceptions include hardware conditions (such as an arithmetic overflow or a memory access violation) or signaled software exceptions (for example, an exception signaled because a file could not be found).

Operating system conventions specify how, and in what order, various condition handlers established by the operating system, the debugger, or your own program are invoked---for example, the primary handler, call frame (application-declared) handlers, and so on. Section 14.5.3 describes condition handling when you are using the debugger. See the OpenVMS Run-Time Library Routines Volume for additional general information about condition handling.

Tools for debugging exceptions and condition handlers include the following:

14.5.1 Setting Breakpoints or Tracepoints on Exceptions

When you enter a SET BREAK/EXCEPTION or SET TRACE/EXCEPTION command, you direct the debugger to treat any exception generated by your program as a breakpoint or tracepoint. As a result of a SET BREAK/EXCEPTION command, if your program generates an exception, the debugger suspends execution, reports the exception and the line where execution is paused, and prompts for commands. The following example shows the effect:


DBG> SET BREAK/EXCEPTION
DBG> GO
   .
   .
   .
%SYSTEM-F-INTDIV, arithmetic trap, integer divide by zero at PC=0000066C, PSL=03C00022 
break on exception preceding TEST\%LINE 13 
     6:         X := 3/Y;
DBG>

Note that an exception breakpoint (or tracepoint) is triggered even if your program has a condition handler to handle the exception. The SET BREAK/EXCEPTION command causes a breakpoint to occur before any handler can execute (and possibly dismiss the exception). Without the exception breakpoint, the handler will be executed, and the debugger would get control only if no handler dismissed the exception (see Section 14.5.2 and Section 14.5.3).

The following command line is useful for identifying where an exception occurred. It causes the debugger to automatically display the sequence of active calls and the PC value at an exception breakpoint:


DBG> SET BREAK/EXCEPTION DO (SET MODULE/CALLS; SHOW CALLS)

You can also create a screen-mode DO display that issues a SHOW CALLS command whenever the debugger interrupts execution. For example:


DBG> DISPLAY CALLS DO (SET MODULE/CALLS; SHOW CALLS)

An exception tracepoint (established with the SET TRACE/EXCEPTION command) is like an exception breakpoint followed by a GO command without an address expression specified.

An exception breakpoint cancels an exception tracepoint, and vice versa.

To cancel exception breakpoints or tracepoints, use the CANCEL BREAK/EXCEPTION or CANCEL TRACE/EXCEPTION command, respectively.

14.5.2 Resuming Execution at an Exception Breakpoint

When an exception breakpoint is triggered, execution is paused before any application-declared condition handler is invoked. When you resume execution from the breakpoint with the GO, STEP, or CALL commands, the behavior is as follows:

The following Fortran example shows how to determine the presence of a condition handler at an exception breakpoint and how a STEP command, entered at the breakpoint, enables you to step into the handler.

At the exception breakpoint, the SHOW CALLS command indicates that the exception was generated during a call to routine SYS$QIOW:


DBG> SET BREAK/EXCEPTION
DBG> GO
   .
   .
   .
%SYSTEM-F-SSFAIL, system service failure exception, status=0000013C, PC=7FFEDE06, PSL=03C00000 
break on exception preceding SYS$QIOW+6
DBG> SHOW CALLS
module name  routine name       line       rel PC    abs PC 
              SYS$QIOW                         00000006  7FFEDE06 
*EXC$MAIN     EXC$MAIN            23      0000003B  0000063B
DBG>

On VAX processors, the following SHOW STACK command indicates that no handler is declared in routine SYS$QIOW. However, one level down the call stack, routine EXC$MAIN has declared a handler named SSHAND:


DBG> SHOW STACK
stack frame 0 (2146296644) 
    condition handler: 0 
       SPA:            0 
       S:              0 
       mask:           ^M<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11> 
       PSW:            0020 (hexadecimal) 
    saved AP:          2146296780 
    saved FP:          2146296704 
    saved PC:          EXC$MAIN\%LINE 25
   .
   .
   .
stack frame 1 (2146296704) 
    condition handler: SSHAND 
       SPA:            0 
       S:              0 
       mask:           ^M<R11> 
       PSW:            0000 (hexadecimal) 
    saved AP:          2146296780 
    saved FP:          2146296760 
    saved PC:          SHARE$DEBUG+2217
   .
   .
   .
 

At this exception breakpoint, entering a STEP command enables you to step directly into condition handler SSHAND:


DBG> STEP
stepped to routine SSHAND 
     2:        INTEGER*4 FUNCTION SSHAND (SIGARGS, MECHARGS)
DBG> SHOW CALLS
 module name  routine name    line     rel PC    abs PC 
*SSHAND       SSHAND            2    00000002  00000642 
----- above condition handler called with exception 0000045C: 
%SYSTEM-F-SSFAIL, system service failure exception, status=0000013C, PC=7FFEDE06, PSL=03C00000 
----- end of exception message 
              SYS$QIOW                 00000006  7FFEDE06 
*EXC$MAIN     EXC$MAIN         23      0000003B  0000063B
DBG>

The debugger symbolizes the addresses of condition handlers into names if that is possible. However, note that with some languages, exceptions are first handled by a Run-Time Library (RTL) routine, before any application-declared condition handler is invoked. In such cases, the address of the first condition handler might be symbolized to an offset from an RTL shareable image address.


Previous Next Contents Index