[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

HP OpenVMS Delta/XDelta Debugger Manual


Previous Contents Index


Chapter 3
Debugging Programs

When you use DELTA or XDELTA, there are no prompts, few symbols, and one error message. You move through program code by referring directly to address locations. This chapter provides directions for the following actions:

  • Referencing addresses
  • Referencing registers, the PSL or PS, and the stack
  • Interpreting the error message
  • Debugging kernel mode code under certain conditions
  • Debugging an installed, protected, shareable image
  • Using XDELTA on multiprocessor computers
  • Debugging code when single-stepping fails (Alpha only)
  • Debugging code that does not match the compiler listings (Alpha and I64 only)

For examples of DELTA debugging sessions on VAX and Alpha, refer respectively to Appendix A and Appendix B.

3.1 Referencing Addresses

When using DELTA or XDELTA to debug programs, you move through the code by referring to addresses. To help you identify address locations within your program, use a list file and a map file. The list file (.LIS) lists each instruction and its offset value from the base address of the program section. The full map file (.MAP) lists the base addresses for each section of your program. To determine the base address of a device driver program, refer to the OpenVMS VAX Device Support Manual1.

Once you have the base addresses of the program sections, locate the instruction in the list file where you want to start the debugging work. Add the offset from the list program to the base address from the map file. Remember that all calculations of address locations are done in hexadecimal. You can use DELTA/XDELTA to do the calculations for you with the = command.

To make address referencing easier, you can use offsets to a base address. Then you do not have to calculate all address locations. First, place the base address into a base register. Then move to a location using the offset to the base address stored in the register.

Whenever DELTA/XDELTA displays an address, it will display a relative address if the offset falls within the permitted range (see the ;X command in Chapter 4).

3.1.1 Referencing Addresses (VAX Only)

On VAX, to reference addresses during a DELTA debug session, use the following example as a guide. The example uses a simple VAX MACRO program (EXAMPLE.MAR). You can also use the same commands in an XDELTA debugging session.


0000    1   .title  example
0000    2
0000    3   .entry  start   ^M<r3,r4>
0002    4           clrl    r3
0004    5           movl    #5,r4
0007    6   10$:    addl    r4,r3
000A    7           sobgtr  r4,10$
000D    8           ret
000E    9
000E   10   .end    start

The following procedure generates information to assist you with address referencing:

  1. Use the /LIST qualifier to assemble the program and generate the list file.
    To generate the list file for the previous example, use the following command:


    $ MACRO/LIST EXAMPLE
    
  2. Use the /MAP qualifier with the link command to generate the full map file (.MAP file). Make sure that the default /DEBUG or /TRACEBACK qualifier is active for your link command. If not, specify /DEBUG or /TRACEBACK along with the /MAP qualifier.
    To generate the map file for the example program, use the following command:


    $ LINK/MAP EXAMPLE
    
  3. Refer to the Program Section Synopsis of the map file, locate the section that you want to debug, and look up the base address.
    For the example program, the map file is EXAMPLE.MAP. A portion of the Program Section Synopsis is shown below. The first section of the program has a base address of 200.


                    +--------------------------+
                    ! Program Section Synopsis !
                    +--------------------------+
    
    Psect Name      Module Name   Base     End           Length
    ----------      -----------   ----     ---           ------
    
    . BLANK .                   00000200 0000020D 0000000E (         14.)
                    EXAMPLE     00000200 0000020D 0000000E (         14.)
    
  4. Refer to the list file for the location of the specific instruction where you want to start debugging.
    For the example program, start with the second instruction (MOVL #5,R4) with an offset of 4.
  5. Enable DELTA using the following commands:


    $ DEFINE LIB$DEBUG SYS$LIBRARY:DELTA
    $ RUN/DEBUG EXAMPLE
    
  6. If you want to store the base address in a base register, use the ;X command to load the base register.
    For the example program, use the following DELTA/XDELTA command to store the base address 200 in base register 0.


    200,0;X [Return]
    
  7. Now you can move to specific address locations.
    For example, if you want to place a breakpoint at the second instruction (MOVL #5,R4), you would calculate the address as 200 (base address) plus 4 (offset), or 204, and specify the ;B command as follows:


    204;B [Return]
    

    Alternatively, if you stored the base address in the base register, you could use the address expression X0+4 (or "X0 4", where the + sign is implied), as follows:


    X0+4;B [Return]
    

Reverse this technique to find an instruction displayed by DELTA/XDELTA in the .LIS file, as follows:

  1. Note the address of the instruction you want to locate in the .LIS file.
    For example, DELTA/XDELTA displays the following instruction at address 020A:


    20A!  sobgtr  r4,00000207
    

    The following steps allow you to find the instruction at location 207:
  2. Refer to the .MAP file and identify the PSECT and MODULE where the address of the instruction is located. Check the base address value and the end address value of each PSECT and MODULE. When the instruction address is between the base and end address values, record the PSECT and MODULE names.
    In the example, the instruction address is located in the EXAMPLE module (.BLANK. psect). The address instruction, 207, is between the base address 200 and the end address 20D.
  3. Subtract the base address from the instruction address. Remember that all calculations are in hexadecimal and that you can use the DELTA/XDELTA = command to do the calculations. The result is the offset.
    For the example, subtract the base address 200 from the instruction address 207. The offset is 7.
  4. Refer to the .LIS file. Look up the MODULE and then find the correct PSECT. Look for the offset value you calculated in the previous step.
    In the example, there is only one PSECT and MODULE. Look up the instruction at offset 7. The program is branching to the following instruction:


    10$:   addl r4,r3
    
    
    

3.1.2 Referencing Addresses (Alpha and I64 Only)

On Alpha and I64, to reference addresses during a DELTA debug session, use the following example as a guide. The example uses a simple C program (HELLO.C). You can also use the same commands in an XDELTA debug session.


 #include <stdio.h>

 main()
 {
  printf("Hello world\n");
 }

The following procedure generates information to assist you with the address referencing:

  1. Use the /LIST and /MACHINE_CODE qualifiers to compile the program and generate the list file containing the Alpha machine instructions.
    To generate the list file for the previous example, use the following command:


       $ cc/list/machine_code hello
    

    The compiler will generate the following Alpha code in the machine code portion of the listing file:


       .PSECT $CODE, OCTA, PIC, CON, REL, LCL, SHR,-
        EXE, NORD, NOWRT
    0000    main::                                                      ; 000335
    0000            LDA     SP, -32(SP)             ; SP, -32(SP)
    0004            LDA     R16, 48(R27)            ; R16, 48(R27)      ; 000337
    0008            STQ     R27, (SP)               ; R27, (SP)         ; 000335
    000C            MOV     1, R25                  ; 1, R25            ; 000337
    0010            STQ     R26, 8(SP)              ; R26, 8(SP)        ; 000335
    0014            STQ     FP, 16(SP)              ; FP, 16(SP)
    0018            LDQ     R26, 32(R27)            ; R26, 32(R27)      ; 000337
    001C            MOV     SP, FP                  ; SP, FP            ; 000335
    0020            LDQ     R27, 40(R27)            ; R27, 40(R27)      ; 000337
    0024            JSR     R26, DECC$GPRINTF       ; R26, R26
    0028            MOV     FP, SP                  ; FP, SP            ; 000338
    002C            LDQ     R28, 8(FP)              ; R28, 8(FP)
    0030            LDQ     FP, 16(FP)              ; FP, 16(FP)
    0034            MOV     1, R0                   ; 1, R0
    0038            LDA     SP, 32(SP)              ; SP, 32(SP)
    003C            RET     R28                     ; R28
    

    Notice the statement numbers on the far right of some of the lines. These numbers correspond to the source line statement numbers from the listing file as shown next:


    335 main()
    336 {
    337     printf("Hello world\n");
    338 }
    
  2. Use the /MAP qualifier with the link command to generate the full map file (.MAP file). To produce a debuggable image, make sure that either /DEBUG or /TRACEBACK (the default) is also specified with the link command.
    To generate the map file for the example program, use the following command:


       $ LINK/MAP/FULL HELLO
    
  3. Refer to the Program Section Synopsis of the map file. Locate the code section that you want to debug and its base address.
    For the example program, the map file is HELLO.MAP. A portion of the Program Section Synopsis is shown below. The $CODE section of the program has a base address of 20000.


      +--------------------------+
      ! Program Section Synopsis !
      +--------------------------+
    
    Psect Name      Module Name       Base     End           Length
    ----------      -----------       ----     ---           ------
    $LINKAGE                        00010000 0001007F 00000080 (        128.)
                    HELLO           00010000 0001007F 00000080 (        128.)
    $CODE                           00020000 000200BB 000000BC (        188.)
                    HELLO           00020000 000200BB 000000BC (        188.)
    
  4. Refer to the list file for the location where you want to start debugging. First find the source line statement number. Next find that statement number in the machine code listing portion of the list file. This is the specific instruction where you want to start debugging.
    For the example program, source statement 337 is the following:


     printf("Hello world\n");
    

    Search the machine code listing for statement 337. The first occurrence is the instruction at offset 4 from the start of "main::" and the base of the $CODE PSECT.
  5. Enable DELTA using the following commands:


       $ DEFINE LIB$DEBUG SYS$LIBRARY:DELTA
       $ RUN/DEBUG HELLO
    
  6. If you want to store the base address in a base register, use the ;X command to load the base register.
    For the example program, use the following DELTA/XDELTA command to store the base address of 20000 in base register 0.


       20000,0;X
    
  7. Now you can move to specific address locations.
    For example, if you want to place a breakpoint at offset 4, you would calculate the address as 20000 (base address) plus 4 (offset), or 20004, and specify the ;B command as follows:


       20004;B
    

    Alternatively, if you stored the base address in the base register, you could use the address expression X0+4 (or "X0 4", where the + sign is implied) to set the breakpoint as follows:


       X0+4;B
    

Reverse this technique to find an instruction displayed by DELTA/XDELTA in the .LIS file, as follows:

  1. Note the address of the instruction you want to locate in the .LIS file.
    For example, DELTA/XDELTA displays the following instruction at address 20020:


       20020!  LDQ             R27,#X0028(R27)
    

    The following steps allow you to find this instruction in the .LIS file.
  2. Refer to the .MAP file, and identify the psect and module where the address of the instruction is located. Check the base address value and the end address value of each psect and module. When the instruction address is between the base and end address values, record the psect and module names.
    In the example, the instruction address is located in the HELLO module ($CODE PSECT). The address, 20020, is between the base address 20000 and the end address 200BB.
  3. Subtract the base address from the instruction address. Remember that all calculations are in hexadecimal and that you can use the DELTA/XDELTA = command to do the calculations. The result is the offset.
    For example, subtract the base address of 20000 from the instruction address 20020. The offset is 20.
  4. Refer to the .LIS file. Look up the module and then find the correct psect. Look for the offset value you calculated in the previous step.
    In the example, there are two psects and one module but only one $CODE psect. Look up the instruction at offset 20, and you will find the following in the .LIS file:


    0020        LDQ R27, 40(R27)            ; R27, 40(R27)      ; 000337
    
    
    

Note

1 This manual has been archived but is available on the OpenVMS Docmentation CD-ROM.

3.2 Referencing Registers

When using DELTA or XDELTA to debug programs, you can view the contents of registers. The following sections describe the types of registers that are referenced by each OpenVMS platform.

3.2.1 Referencing Registers (VAX Only)

On VAX, to view the contents of the 16 general registers (including the program counter and the stack pointer) and the processor status longword (PSL), use the same DELTA/XDELTA commands as you use to view the contents of any memory location (for example, the /, LINEFEED, and the ESC commands). The symbols used to identify the locations of the registers and PSL are as follows:

  • The general registers are referred to by the symbol R and a hexadecimal number from 016 to F16 representing the number of the register. For example, general register 110 is R116 and general register 1010 is RA16. The stack pointer is located in general register 1410, RE16. The program counter is in general register 1510, RF16.
  • Upon entry to DELTA or XDELTA, the PSL is stored in the longword directly following the longword representing general register F16. Reference it by using the general register F16 symbol plus a longword (RF+4).

3.2.2 Referencing Registers (Alpha Only)

On Alpha, to view the contents of the 32 integer registers, the program counter (PC), the stack pointer (SP), the processor status (PS), the 32 floating point registers, the floating point control register (FPCR), and the internal processor registers (IPRs), use the same DELTA/XDELTA commands that you use to view the contents of any memory location. These commands include /, LINEFEED, and ESC. The symbols for identifying these registers follow:

  • Integer registers are referenced by the symbol R and a decimal number from 0 to 31. For example, register 110 is R110 and register 1010 is R1010. (Decimal notation differs from the original implementation on VAX which uses hexadecimal notation.)
  • PC is referenced symbolically by PC.
  • PS is referenced symbolically by PS.
  • FP is referenced by R29.
  • SP is referenced by R30.
  • Floating point registers are referenced by FP and a decimal number from 0 to 31. For example, floating point register 110 is FP110 and floating point register 1010 is FP1010.
  • FPCR is treated like any other floating point register except, to explicitly open it, you specify FPCR/.
  • Internal processor registers (IPRs) are accessed symbolically, for example, P(ASTEN). For IPR names, see the Alpha Architecture Reference Manual.

Floating point registers can be accessed from DELTA and from XDELTA but only if floating point arithmetic is enabled in the current process.

DELTA runs in the context of a process. Access to floating point registers is enabled as soon as the first floating point instruction in the code being examined is executed. Access is disabled as soon as that image completes execution.

When the system enters XDELTA, some process is the current process, and that current process may not be obvious. If that process happens to have floating point enabled at the time (because a floating point instruction had executed and the image containing the floating point instruction was still executing), then you can access the floating point registers. Otherwise, you cannot. XDELTA checks the FEN (floating point enable) IPR (internal processor register) to see if it needs to provide access to floating point registers.

3.2.3 Referencing Registers (I64 Only)

On I64, you can reference the following kinds of registers: integer, floating, application, branch, control, special purpose, and software equivilents of special OpenVMS symbolic locations.

These registers are identified by the following symbols:

  • General registers --- R0 through R127
  • Floating registers --- F0 through F127
  • Branch registers --- B0 through B7
  • Predicate registers --- P0 through P63
  • Application registers --- AR16 (RSC), AR17 (BSP), AR18 (BSPSTORE), AR19 (RNAT), AR25 (CSD), AR26 (SSD), AR32 (CCV), AR36 (UNAT), AR64 (PFS), AR65 (LC), AR66 (EC)
  • PC --- A program counter, obtained from the hardware IP register and the ri field of the PSR register

3.3 Interpreting the Error Message

When you make an error entering a command in DELTA or XDELTA, you get the "Eh?" error message. This is the only error message generated by DELTA and XDELTA. It is displayed under the following circumstances:

  • You entered characters that DELTA/XDELTA does not recognize
  • You entered a command incorrectly
  • You exceeded the limits of the command (for example, trying to set another breakpoint when all breakpoints are used)
  • You attempted to display a particular memory address and one or more of the following is true:
    • location is not a valid memory address
    • you have no privilege to read the address
    • the process to which the read applies does not exist (DELTA only)
  • You attempted to change a particular memory address (including setting a breakpoint) and one or more of the following is true:
    • the location is not a valid memory address
    • you have no privilege to write to the address
    • the process to which the write applies does not exist (DELTA only)

On Alpha, the error message is also displayed if you are unable to single-step or proceed due to no write access to the address of the next instruction.

On I64, the error message is also displayed if you are unable to step over a subroutine call due to no write access to the address of the next instruction.

3.4 Debugging Kernel Mode Code Under Certain Conditions

On Alpha and VAX, some programs exist which, while running in process space, change mode to kernel and raise IPL. Typically, this code is debugged with both DELTA and XDELTA. DELTA is used to debug the kernel mode code at IPL zero. XDELTA is used to debug the code at elevated IPL. (DELTA does not work at elevated IPL.)

Before you can debug such code with XDELTA on an Alpha or VAX computer, you must do some setup work.

3.4.1 Setup Required (VAX Only)

On VAX, some setup work is required before you can debug kernel mode code that runs in process space at an elevated IPL. Before you access XDELTA, do the following:

  1. Ensure that page faults do not occur at elevated IPL by locking into memory (or the working set) the code that runs at elevated IPL.
  2. Make the code writable if you plan to do anything more than single-step through your code (such as set breakpoints, step-overs, and so forth). (By default, code pages are read only.) To make the code writable, modify the code psect attributes in the link options file or set the affected code pages to writable with $SETPRT.


Previous Next Contents Index