|
HP OpenVMS Delta/XDelta Debugger Manual
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 (I64 and
Alpha only)
For examples of DELTA debugging sessions on various OpenVMS platforms,
see Appendix A for I64, Appendix B for Alpha, and Appendix C for
VAX.
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, see 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 (I64 and Alpha Only)
On I64 and Alpha, to reference addresses during a DELTA debug session,
use the following OpenVMS Alpha 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:
- 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 }
|
- 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:
- See 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.)
|
- See 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:
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.
- Enable DELTA using the following commands:
$ DEFINE LIB$DEBUG SYS$LIBRARY:DELTA
$ RUN/DEBUG HELLO
|
- 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.
- 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:
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:
Reverse this technique to find an instruction displayed by DELTA/XDELTA
in the .LIS file, as follows:
- 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.
- See 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.
- 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.
- See 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
|
3.1.2 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:
- 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:
- 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:
- See 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.)
|
- See 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.
- Enable DELTA using the following commands:
$ DEFINE LIB$DEBUG SYS$LIBRARY:DELTA
$ RUN/DEBUG EXAMPLE
|
- 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.
- 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:
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:
Reverse this technique to find an instruction displayed by DELTA/XDELTA
in the .LIS file, as follows:
- 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:
The following steps allow you to find the instruction at location
207:
- See 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.
- 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.
- See 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:
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 (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.
Table 3-1 lists the Intel Itanium registers and symbols by which
they are identified.
Table 3-1 Intel Itanium Registers and their Associated Symbols
Register |
Symbol |
General
|
R0 through R127
|
Floating
|
FP0 through FP127
|
Branch
|
BR0 through BR7
|
Predicate
|
P0 through P63
|
Application
|
AR16 (RSC), AR17 (BSP), AR18 (BSPSTORE), AR19 (RNAT), AR25 (CSD), AR26
(SSD), AR32 (CCV), AR36 (UNAT), AR64 (PFS), AR65 (LC), AR66 (EC)
|
Control
|
CR0 (DCR), CR1 (ITM), CR2 (IVA), CR8 (PTA), CR16 (IPSR), CR17 (ISR),
CR19 (IIP), CR20 (IFA), CR21 (ITIR), CR22 (IIPA), CR23 (IFS), CR24
(IIM), CR25 (IHA),CR65 (IVR)
|
In addition, there is a program counter (PC) register, which is
obtained from the hardware IP register and the
ri
field of the PSR register.
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 (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.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 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.
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.
3.4 Debugging Kernel Mode Code Under Certain Conditions
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, you must complete some
setup work.
|