The descriptions of basic debugging tasks for assembler refer to the following assembler program.
Example: sample assembler program for debugging
Refer to the following topics for more information related to the material discussed in this topic.
The program below is used in various topics to demonstrate debugging tasks.
To run this sample program, do the following steps:
LDD (SUBXMP,DISPARM)
This program is a small example of an assembler main routine (SUBXMP) that calls an assembler subroutine (DISPARM).
Load module: XMPLOAD
SUBXMP.ASM
**************************************************************
* *
* NAME: SUBXMP *
* *
* A simple main assembler routine that brings up *
* Language Environment, calls a subroutine, and *
* returns with a return code of 0. *
* *
**************************************************************
SUBXMP CEEENTRY PPA=XMPPPA,AUTO=WORKSIZE
USING WORKAREA,R13
* Invoke CEEMOUT to issue the greeting message
CALL CEEMOUT,(HELLOMSG,DEST,FBCODE),VL,MF=(E,CALLMOUT)
* No plist to DISPARM, so zero R1. Then call it.
SLR R0,R0
ST R0,COUNTER
LA R0,HELLOMSG
SR R01,R01 ssue a message
CALL DISPARM CALL1
* Invoke CEEMOUT to issue the farewell message
CALL CEEMOUT,(BYEMSG,DEST,FBCODE),VL,MF=(E,CALLMOUT)
* Terminate Language Environment and return to the caller
CEETERM RC=0
* CONSTANTS
HELLOMSG DC Y(HELLOEND-HELLOSTR)
HELLOSTR DC C'Hello from the sub example.'
HELLOEND EQU *
BYEMSG DC Y(BYEEND-BYESTART)
BYESTART DC C'Terminating the sub example.'
BYEEND EQU *
DEST DC F'2' Destination is the LE message file
COUNTER DC F'-1'
XMPPPA CEEPPA , Constants describing the code block
* The Workarea and DSA
WORKAREA DSECT
ORG *+CEEDSASZ Leave space for the DSA fixed part
CALLMOUT CALL ,(,,),VL,MF=L 3-argument parameter list
FBCODE DS 3F Space for a 12-byte feedback code
DS 0D
WORKSIZE EQU *-WORKAREA
PRINT NOGEN
CEEDSA , Mapping of the dynamic save area
CEECAA , Mapping of the common anchor area
R0 EQU 0
R01 EQU 1
R13 EQU 13
END SUBXMP Nominate SUBXMP as the entry point
DISPARM.ASM
**************************************************************
* *
* NAME: DISPARM *
* *
* Shows an assembler subroutine that displays inbound *
* parameters and returns. *
* *
**************************************************************
DISPARM CEEENTRY PPA=PARMPPA,AUTO=WORKSIZE,MAIN=NO
USING WORKAREA,R13
* Invoke CEE3PRM to retrieve the command parameters for us
SLR R0,R0
ST R0,COUNTER
CALL CEE3PRM,(CHARPARM,FBCODE),VL,MF=(E,CALL3PRM) CALL2
* Check the feedback code from CEE3PRM to see if everything worked.
CLC FBCODE(8),CEE000
BE GOT_PARM
* Invoke CEEMOUT to issue the error message for us
CALL CEEMOUT,(BADFBC,DEST,FBCODE),VL,MF=(E,CALLMOUT)
B GO_HOME Time to go....
GOT_PARM DS 0H
* See if the parm string is blank.
LA R1,1
SAVECTR ST R1,COUNTER
CL R1,=F'5' BUMPCTR
BH LOOPEND
LA R1,1(,R1)
B SAVECTR
LOOPEND DS 0H
CLC CHARPARM(80),=CL80' ' Is the parm empty?
BNE DISPLAY_PARM No. Print it out.
* Invoke CEEMOUT to issue the error message for us
CALL CEEMOUT,(NOPARM,DEST,FBCODE),VL,MF=(E,CALLMOUT)
B GO_TEST Time to go....
DISPLAY_PARM DS 0H
* Set up the plist to CEEMOUT to display the parm.
LA R0,2
ST R0,COUNTER
LA R02,80 Get the size of the string
STH R02,BUFFSIZE Save it for the len-prefixed string
* Invoke CEEMOUT to display the parm string for us
CALL CEEMOUT,(BUFFSIZE,DEST,FBCODE),VL,MF=(E,CALLMOUT)
* AMODE Testing
GO_TEST DS 0H
L R15,INAMODE24@
BSM R14,R15
InAMode24 Equ *
LA R1,DEST
O R1,=X'FF000000'
L R15,0(,R1)
LA R15,2(,R15)
ST R15,0(,R1)
L R15,INAMODE31@
BSM R14,R15
InAMode31 Equ *
* Return to the caller
GO_HOME DS 0H
LA R0,3
ST R0,COUNTER
CEETERM RC=0
* CONSTANTS
DEST DC F'2' Destination is the LE message file
CEE000 DS 3F'0' Success feedback code
InAMode24@ DC A(InAMode24)
InAMode31@ DC A(InAMode31+X'80000000')
BADFBC DC Y(BADFBEND-BADFBSTR)
BADFBSTR DC C'Feedback code from CEE3PRM was nonzero.'
BADFBEND EQU *
NOPARM DC Y(NOPRMEND-NOPRMSTR)
NOPRMSTR DC C'No user parm was passed to the application.'
NOPRMEND EQU *
PARMPPA CEEPPA , Constants describing the code block
* ===================================================================
WORKAREA DSECT
ORG *+CEEDSASZ Leave space for the DSA fixed part
CALL3PRM CALL ,(,),VL,MF=L 2-argument parameter list
CALLMOUT CALL ,(,,),VL,MF=L 3-argument parameter list
FBCODE DS 3F Space for a 12-byte feedback code
COUNTER DS F
BUFFSIZE DS H Halfword prefix for following string
CHARPARM DS CL255 80-byte buffer
DS 0D
WORKSIZE EQU *-WORKAREA
PRINT NOGEN
CEEDSA , Mapping of the dynamic save area
CEECAA , Mapping of the common anchor area
MYDATA DSECT ,
MYF DS F
R0 EQU 0
R1 EQU 1
R2 EQU 2
R3 EQU 3
R4 EQU 4
R5 EQU 5
R6 EQU 6
R7 EQU 7
R8 EQU 8
R9 EQU 9
R10 EQU 10
R11 EQU 11
R12 EQU 12
R13 EQU 13
R14 EQU 14
R15 EQU 15
R02 EQU 2
END
Before you can debug an assembler program, you must define the compilation unit (CU) as an assembler CU and load the debug data for the CU. This can only be done for a CU that is currently known to Debug Tool as a disassembly CU.
You use the LOADDEBUGDATA command (abbreviated as LDD) to define a disassembly CU as an assembler CU and to cause the debug data for this CU to be loaded. When you run the LDD command, you can specify either a single CU name or a list of CU names enclosed in parenthesis. Each of the names specified must be either:
When the CU name is currently known to Debug Tool, the CU is immediately marked as an assembler CU and an attempt is made to load the debug data as follows:
When the CU name specified on the LDD command is not currently known to Debug Tool, a message is issued and the LDD command is deferred until a CU by that name becomes known (appears). At that time, the CU is automatically created as an assembler CU and an attempt is made to load the debug data using the default data set name or the current SET DEFAULT LISTINGS specification.
After you have entered an LDD command for a CU, you cannot view the CU as a disassembly CU.
If Debug Tool cannot find the associated assembler debug data after you have entered an LDD command, the CU is an assembler CU rather than a disassembly CU. You cannot enter another LDD command for this CU. However, you can enter a SET DEFAULT LISTING command or a SET SOURCE command to cause the associated debug data to be loaded from a different data set.
As described in the previous section, you can use the LDD command to identify a CU as an assembler CU before the CU has become known to Debug Tool. This is known as a deferred LDD. In this case, whenever the CU appears, it is immediately marked as an assembler CU and an attempt is made to load the debug data from the default data set name or from the data set currently specified by SET DEFAULT LISTINGS.
If the debug data cannot be found in this way, you must using the SET SOURCE or SET DEFAULT LISTINGS command after the CU appears to cause the debug data to be loaded from the correct data set. You can do this using a command such as:
AT APPEARANCE mycu SET SOURCE (mycu) hlq.qual1.dsn
Alternatively, you might wait until you have stopped for some other reason after "mycu" has appeared and then use the SET SOURCE or SET DEFAULT LISTING commands to direct Debug Tool to the proper data set.
If a CU from which valid assembler debug data has been loaded goes away and then reappears (e.g., the load module is deleted and then reloaded), the CU is immediately marked as an assembler CU and the debug data is reloaded from the data set from which it was successfully loaded originally.
You do not need to (and cannot) issue another LDD for that CU because it is already known as an assembler CU and the debug data has already been loaded.
Debug Tool treats each assembler CSECT as a separate compilation unit (CU). If your assembler source contains more than one CSECT, then the EQALANGX file that you create will contain debug information for all the CSECTs.
In most cases, all of the CSECTs in the assembly will be present in the load module or program object. However, in some cases, one or more of the assemblies might not be present or might be replaced by other CSECTs of the same name. There are, therefore, two ways of loading the debug data for assemblies containing multiple CSECTs:
The following sections use an example assembly that generates two CSECTs: MYPROG and MYPROGA. The debug information for both of these CSECTs is in the data set yourid.EQALANGX(MYPROG).
If SET LDD ALL is in effect, follow the process described in this section. This process is the easiest way to load debug data for assemblies containing multiple CSECTs when all of the CSECTs are present in the load module or program object.
When you enter the command LDD MYPROG, Debug Tool finds and loads the debug data for both MYPROG and MYPROGA. After the debug data is loaded, Debug Tool uses the debug data to create two CUs, one for MYPROG and another for MYPROGA.
If SET LDD SINGLE is in effect, follow the process described in this section.
When you enter the command LDD MYPROG, Debug Tool finds and loads the debug information for both MYPROG and MYPROGA. However, because you specified only MYPROG on the LDD command and SET LDD SINGLE is in effect, Debug Tool uses only the debug information for MYPROG. Then, if you enter the command LDD MYPROGA, Debug Tool does the following steps:
After you have loaded the debug data for both of the CSECTs in the assembly, you can begin debugging either of the compile units. Although the contents of both CSECTs appear in the source listing, you can only set breakpoints in the compile unit to which you are currently qualified.
When you look at the source listing, all lines contained in a CSECT to which you are not currently qualified have an asterisk immediately before the offset field and following the statement number. If you want to set a line or statement breakpoint on a statement that has this asterisk, you must first qualify to the containing compile unit by using the following command:
SET QUALIFY CU compile_unit_name;
After you enter this command, the asterisks are removed from the line on which you wanted to set a breakpoint. The absence of the asterisk indicates that you can set a line or statement breakpoint on that line.
You cannot use the SET QUALIFY command to qualify to an assembler compile unit until after you have loaded the debug data for that compile unit.
This topic describes how to halt just after a routine is called by using the AT ENTRY command. The Example: sample assembler program for debugging is used to describe these commands.
To halt after the DISPARM routine is called, enter the following command:
AT ENTRY DISPARM
To halt after the DISPARM routine is called and only when R1 equals 0, enter the following command:
AT ENTRY DISPARM WHEN R1=0;
The AT CALL command is not supported for assembler routines. Do not use the AT CALL command to stop Debug Tool when an assembler routine is called.
If you have many breakpoints set in your program, you can enter the following command to have Debug Tool identify where your program has stopped:
QUERY LOCATION
The Debug Tool Log window displays something similar to the following example:
QUERY LOCATION You are executing commands in the ENTRY XMPLOAD ::> DISPARM breakpoint. The program is currently entering block XMPLOAD ::> DISPARM.
To list the contents of a single variable, move the cursor to an occurrence of the variable name in the Source window and press PF4 (LIST). The value is displayed in the Log window. This is equivalent to entering LIST variable on the command line.
For example, run the SUBXMP program to the statement labeled CALL1 by entering AT 70 ; GO ; on the Debug Tool command line. Scroll up until you see line 67. Move the cursor over COUNTER and press PF4 (LIST). The following appears in the Log window:
LIST ( COUNTER ) COUNTER = 0
To modify the value of COUNTER to 1, type over the COUNTER = 0 line with COUNTER = 1, press Enter to put it on the command line, and press Enter again to issue the command.
To list the contents of the 16 bytes of storage 2 bytes past the address contained in register R0, type the command LIST STORAGE(R0->+2,16) on the command line and press Enter. The contents of the specified storage are displayed in the Log window.
LIST STORAGE( R0 -> + 2 , 16 ) 000C321E C8859393 96408699 969440A3 888540A2 *Hello from the s*
To modify the first two bytes of this storage to X'C182', type the command R0->+2 <2> = X'C182'; on the command line and press Enter to issue the command.
Now step into the call to DISPARM by pressing PF2 (STEP) and step until the line labeled CALL2 is reached. To view the attributes of variable COUNTER, issue the Debug Tool command:
DESCRIBE ATTRIBUTES COUNTER
The result in the Log window is:
ATTRIBUTES for COUNTER Its address is 1B0E2150 and its length is 4 DS F
While you debug an assembler or disassembly program, you might want to determine the symbolic address represented by a hexadecimal address. You can do this by using the LIST command with the %WHERE built-in function. For example, the following command returns a string indicating the symbolic location of X'1BC5C':
LIST %WHERE(X'1BC5C')
After you enter the command, Debug Tool displays the following result:
PROG1+X'12C'
The result indicates that the address X'1BC5C' corresponds to offset X'12C' within CSECT PROG1.
Often a particular part of your program works fine for the first few thousand times, but it fails under certain conditions. Setting a line breakpoint is inefficient because you will have to repeatedly enter the GO command.
Example: sample assembler program for debugging
In the DISPARM program, to stop Debug Tool when the COUNTER variable is set to 3, enter the following command:
AT 78 DO; IF COUNTER ^= 3 THEN GO; END;
Line 78 is the line labeled BUMPCTR . The command causes Debug Tool to stop at line 78. If the value of COUNTER is not 3, the program continues. The command causes Debug Tool to stop on line 78 only if the value of COUNTER is 3.
Often when you get close to a programming error, you want to know what sequence of calls lead you to the programming error. This sequence is called traceback or traceback of callers. To get the traceback information, enter the following command:
LIST CALLS
Example: sample assembler program for debugging
For example, if you run the SUBXMP example with the following commands, the Log window displays the traceback of callers:
AT ENTRY DISPARM GO LIST CALLS
The Log window displays information similar to the following:
At ENTRY IN Assembler routine XMPLOAD ::> DISPARM. From LINE 76.1 IN Assembler routine XMPLOAD ::> SUBXMP.
While your program is running, some storage might unexpectedly change its value and you want to find out when and where this happened. Consider the following example, where the program finds a value unexpectedly modified:
L R0,X'24'(R3)
To find the address of the operand being loaded, enter the following command:
LIST R3->+X'24'
Suppose the result is X'00521D42'. To set a breakpoint that watches for a change in storage values starting at that address and for the next 4 bytes, enter the following command:
AT CHANGE %STORAGE(X'00521D42',4)
When the program runs, Debug Tool stops if the value in this storage changes.