The descriptions of basic debugging tasks for COBOL refer to the following COBOL program.
Example: sample COBOL 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.
This program calls two subprograms to calculate a loan payment amount and the future value of a series of cash flows. It uses several COBOL intrinsic functions.
Main program COBCALC
**********************************************************
* COBCALC *
* *
* A simple program that allows financial functions to *
* be performed using intrinsic functions. *
* *
**********************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. COBCALC.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 PARM-1.
05 CALL-FEEDBACK PIC XX.
01 FIELDS.
05 INPUT-1 PIC X(10).
01 INPUT-BUFFER-FIELDS.
05 BUFFER-PTR PIC 9.
05 BUFFER-DATA.
10 FILLER PIC X(10) VALUE "LOAN".
10 FILLER PIC X(10) VALUE "PVALUE".
10 FILLER PIC X(10) VALUE "pvalue".
10 FILLER PIC X(10) VALUE "END".
05 BUFFER-ARRAY REDEFINES BUFFER-DATA
OCCURS 4 TIMES
PIC X(10).
PROCEDURE DIVISION.
DISPLAY "CALC Begins." UPON CONSOLE.
MOVE 1 TO BUFFER-PTR.
MOVE SPACES TO INPUT-1.
* Keep processing data until END requested
PERFORM ACCEPT-INPUT UNTIL INPUT-1 EQUAL TO "END".
* END requested
DISPLAY "CALC Ends." UPON CONSOLE.
GOBACK.
* End of program.
*
* Accept input data from buffer
*
ACCEPT-INPUT.
MOVE BUFFER-ARRAY (BUFFER-PTR) TO INPUT-1.
ADD 1 BUFFER-PTR GIVING BUFFER-PTR.
* Allow input data to be in UPPER or lower case
EVALUATE FUNCTION UPPER-CASE(INPUT-1) CALC1 WHEN "END"
MOVE "END" TO INPUT-1
WHEN "LOAN"
PERFORM CALCULATE-LOAN
WHEN "PVALUE"
PERFORM CALCULATE-VALUE
WHEN OTHER
DISPLAY "Invalid input: " INPUT-1
END-EVALUATE.
*
* Calculate Loan via CALL to subprogram
*
CALCULATE-LOAN.
CALL "COBLOAN" USING CALL-FEEDBACK.
IF CALL-FEEDBACK IS NOT EQUAL "OK" THEN
DISPLAY "Call to COBLOAN Unsuccessful.".
*
* Calculate Present Value via CALL to subprogram
*
CALCULATE-VALUE.
CALL "COBVALU" USING CALL-FEEDBACK.
IF CALL-FEEDBACK IS NOT EQUAL "OK" THEN
DISPLAY "Call to COBVALU Unsuccessful.".
Subroutine COBLOAN
**********************************************************
* COBLOAN *
* *
* A simple subprogram that calculates payment amount *
* for a loan. *
* *
**********************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. COBLOAN.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 FIELDS.
05 INPUT-1 PIC X(26).
05 PAYMENT PIC S9(9)V99 USAGE COMP.
05 PAYMENT-OUT PIC $$$$,$$$,$$9.99 USAGE DISPLAY.
05 LOAN-AMOUNT PIC S9(7)V99 USAGE COMP.
05 LOAN-AMOUNT-IN PIC X(16).
05 INTEREST-IN PIC X(5).
05 INTEREST PIC S9(3)V99 USAGE COMP.
05 NO-OF-PERIODS-IN PIC X(3).
05 NO-OF-PERIODS PIC 99 USAGE COMP.
05 OUTPUT-LINE PIC X(79).
LINKAGE SECTION.
01 PARM-1.
05 CALL-FEEDBACK PIC XX.
PROCEDURE DIVISION USING PARM-1.
MOVE "NO" TO CALL-FEEDBACK.
MOVE "30000 .09 24 " TO INPUT-1.
UNSTRING INPUT-1 DELIMITED BY ALL " "
INTO LOAN-AMOUNT-IN INTEREST-IN NO-OF-PERIODS-IN.
* Convert to numeric values
COMPUTE LOAN-AMOUNT = FUNCTION NUMVAL(LOAN-AMOUNT-IN).
COMPUTE INTEREST = FUNCTION NUMVAL(INTEREST-IN).
COMPUTE NO-OF-PERIODS = FUNCTION NUMVAL(NO-OF-PERIODS-IN).
* Calculate annuity amount required
COMPUTE PAYMENT = LOAN-AMOUNT *
FUNCTION ANNUITY((INTEREST / 12 ) NO-OF-PERIODS).
* Make it presentable
MOVE SPACES TO OUTPUT-LINE
MOVE PAYMENT TO PAYMENT-OUT.
STRING "COBLOAN:_Repayment_amount_for_a_" NO-OF-PERIODS-IN
"_month_loan_of_" LOAN-AMOUNT-IN
"_at_" INTEREST-IN "_interest_is:_"
DELIMITED BY SPACES
INTO OUTPUT-LINE.
INSPECT OUTPUT-LINE REPLACING ALL "_" BY SPACES.
DISPLAY OUTPUT-LINE PAYMENT-OUT.
MOVE "OK" TO CALL-FEEDBACK.
GOBACK.
Subroutine COBVALU
**********************************************************
* COBVALU *
* *
* A simple subprogram that calculates present value *
* for a series of cash flows. *
* *
**********************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. COBVALU.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 CHAR-DATA.
05 INPUT-1 PIC X(10).
05 PAYMENT-OUT PIC $$$$,$$$,$$9.99 USAGE DISPLAY.
05 INTEREST-IN PIC X(5).
05 NO-OF-PERIODS-IN PIC X(3).
05 INPUT-BUFFER PIC X(10) VALUE "5069837544".
05 BUFFER-ARRAY REDEFINES INPUT-BUFFER
OCCURS 5 TIMES
PIC XX.
05 OUTPUT-LINE PIC X(79).
01 NUM-DATA.
05 PAYMENT PIC S9(9)V99 USAGE COMP.
05 INTEREST PIC S9(3)V99 USAGE COMP.
05 COUNTER PIC 99 USAGE COMP.
05 NO-OF-PERIODS PIC 99 USAGE COMP.
05 VALUE-AMOUNT OCCURS 99 PIC S9(7)V99 COMP.
LINKAGE SECTION.
01 PARM-1.
05 CALL-FEEDBACK PIC XX.
PROCEDURE DIVISION USING PARM-1.
MOVE "NO" TO CALL-FEEDBACK.
MOVE ".12 5 " TO INPUT-1.
UNSTRING INPUT-1 DELIMITED BY "," OR ALL " " VALU1
INTO INTEREST-IN NO-OF-PERIODS-IN.
* Convert to numeric values
COMPUTE INTEREST = FUNCTION NUMVAL(INTEREST-IN). VALU2
COMPUTE NO-OF-PERIODS = FUNCTION NUMVAL(NO-OF-PERIODS-IN).
* Get cash flows
PERFORM GET-AMOUNTS VARYING COUNTER FROM 1 BY 1 UNTIL
COUNTER IS GREATER THAN NO-OF-PERIODS.
* Calculate present value
COMPUTE PAYMENT =
FUNCTION PRESENT-VALUE(INTEREST VALUE-AMOUNT(ALL) ). VALU3
* Make it presentable
MOVE PAYMENT TO PAYMENT-OUT.
STRING "COBVALU:_Present_value_for_rate_of_"
INTEREST-IN "_given_amounts_"
BUFFER-ARRAY (1) ",_"
BUFFER-ARRAY (2) ",_"
BUFFER-ARRAY (3) ",_"
BUFFER-ARRAY (4) ",_"
BUFFER-ARRAY (5) "_is:_"
DELIMITED BY SPACES
INTO OUTPUT-LINE.
INSPECT OUTPUT-LINE REPLACING ALL "_" BY SPACES.
DISPLAY OUTPUT-LINE PAYMENT-OUT.
MOVE "OK" TO CALL-FEEDBACK.
GOBACK.
*
* Get cash flows for each period
*
GET-AMOUNTS.
MOVE BUFFER-ARRAY (COUNTER) TO INPUT-1.
COMPUTE VALUE-AMOUNT (COUNTER) = FUNCTION NUMVAL(INPUT-1).
Refer to the following topics for more information related to the material discussed in this topic.
This topic describes how to halt just before or just after a routine is called by using the AT CALL or AT ENTRY commands. The Example: sample COBOL program for debugging is used to describe these commands.
To use the AT CALL command, you must compile the calling program with the TEST compiler option.
To halt just before COBLOAN is called, enter the following command:
AT CALL COBLOAN ;
To use the AT ENTRY command, you must compile the called program with the TEST compiler option.
To halt just after COBVALU is called, enter the following command:
AT ENTRY COBVALU ;
To halt just after COBVALU is called and only when CALL-FEEDBACK equals OK, enter the following command:
AT ENTRY COBVALU WHEN CALL-FEEDBACK = "OK" ;
If you have many breakpoints set in your program, enter the following command to have Debug Tool identify your program has been stopped:
QUERY LOCATION
The Debug Tool Log window displays something similar to the following example:
QUERY LOCATION ; You were prompted because STEP ended. The program is currently entering block COBVALU.
Example: sample COBOL program for debugging
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). Remember that Debug Tool starts after program initialization but before symbolic COBOL variables are initialized, so you cannot view or modify the contents of variables until you have performed a step or run. The value is displayed in the Log window. This is equivalent to entering LIST TITLED variable on the command line. Run the COBCALC program to the statement labeled CALC1 , and enter AT 46 ; GO ; on the Debug Tool command line. Move the cursor over INPUT-1 and press LIST (PF4). The following appears in the Log window:
LIST ( INPUT-1 ) ; INPUT-1 = 'LOAN '
To modify the value of INPUT-1, enter on the command line:
MOVE 'pvalue' to INPUT-1 ;
You can enter most COBOL expressions on the command line.
Now step into the call to COBVALU by pressing PF2 (STEP) and step until the statement labeled VALU2 is reached. To view the attributes of the variable INTEREST, issue the Debug Tool command:
DESCRIBE ATTRIBUTES INTEREST ;
The result in the Log window is:
ATTRIBUTES FOR INTEREST ITS LENGTH IS 4 ITS ADDRESS IS 00011DC8 02 COBVALU:>INTEREST S999V99 COMP
You can use this action as a simple browser for group items and data hierarchies. For example, you can list all the values of the elementary items for the CHAR-DATA group with the command:
LIST CHAR-DATA ;
with results in the Log window appearing something like this:
LIST CHAR-DATA ; 02 COBVALU:>INPUT-1 of 01 COBVALU:>CHAR-DATA = '.12 5 ' Invalid data for 02 COBVALU:>PAYMENT-OUT of 01 COBVALU:>CHAR-DATA is found. 02 COBVALU:>INTEREST-IN of 01 COBVALU:>CHAR-DATA = '.12 ' 02 COBVALU:>NO-OF-PERIODS-IN of 01 COBVALU:>CHAR-DATA = '5 ' 02 COBVALU:>INPUT-BUFFER of 01 COBVALU:>CHAR-DATA = '5069837544' SUB(1) of 02 COBVALU:>BUFFER-ARRAY of 01 COBVALU:>CHAR-DATA = '50' SUB(2) of 02 COBVALU:>BUFFER-ARRAY of 01 COBVALU:>CHAR-DATA = '69' SUB(3) of 02 COBVALU:>BUFFER-ARRAY of 01 COBVALU:>CHAR-DATA = '83' SUB(4) of 02 COBVALU:>BUFFER-ARRAY of 01 COBVALU:>CHAR-DATA = '75' SUB(5) of 02 COBVALU:>BUFFER-ARRAY of 01 COBVALU:>CHAR-DATA = '44'
Refer to the following topics for more information related to the material discussed in this topic.
Often a particular part of your program works fine for the first few thousand times, but it fails under certain conditions. You don't want to just set a line breakpoint because you will have to keep entering GO.
Example: sample COBOL program for debugging
For example, in COBVALU you want to stop at the calculation of present value only if the discount rate is less than or equal to -1 (before the exception occurs). First run COBCALC, step into COBVALU, and stop at the statement labeled VALU1 . To accomplish this, issue these Debug Tool commands at the start of COBCALC:
AT 67 ; GO ; CLEAR AT 67 ; STEP 4 ;
Now set the breakpoint like this:
AT 44 IF INTEREST > -1 THEN GO ; END-IF ;
Line 44 is the statement labeled VALU3 . The command causes Debug Tool to stop at line 44. If the value of INTEREST is greater than -1, the program continues. The command causes Debug Tool to remain on line 44 only if the value of INTEREST is less than or equal to -1.
To force the discount rate to be negative, enter the Debug Tool command:
MOVE '-2 5' TO INPUT-1 ;
Run the program by issuing the GO command. Debug Tool halts the program at line 44. Display the contents of INTEREST by issuing the LIST INTEREST command. To view the effect of this breakpoint when the discount rate is positive, begin a new debug session and repeat the Debug Tool commands shown in this section. However, do not issue the MOVE '-2 5' TO INPUT-1 command. The program execution does not stop at line 44 and the program runs to completion.
Example: sample COBOL program for debugging
Suppose you want to set a breakpoint at entry to COBVALU. COBVALU has been compiled with TEST but the other programs have not. Debug Tool comes up with an empty Source window. You can use the LIST NAMES CUS command to determine if the COBVALU compile unit is known to Debug Tool and then set the appropriate breakpoint using either the AT APPEARANCE or the AT ENTRY command.
Instead of setting a breakpoint at entry to COBVALU in this example, issue a STEP command when Debug Tool initially displays the empty Source window. Debug Tool runs the program until it reaches the entry for the first routine compiled with TEST, COBVALU in this case.
Refer to the following topics for more information related to the material discussed in this topic.
To redirect output normally appearing on the system console to your Debug Tool terminal, enter the following command:
SET INTERCEPT ON CONSOLE ;
Example: sample COBOL program for debugging
For example, if you run COBCALC and issue the Debug Tool SET INTERCEPT ON CONSOLE command, followed by the STEP 3 command, you will see the following output displayed in the Debug Tool Log window:
SET INTERCEPT ON CONSOLE ; STEP 3 ; CONSOLE : CALC Begins.
The phrase CALC Begins. is displayed by the statement DISPLAY "CALC Begins." UPON CONSOLE in COBCALC.
The SET INTERCEPT ON CONSOLE command not only captures output to the system console, but also allows you to input data from your Debug Tool terminal instead of the system console by using the Debug Tool INPUT command. For example, if the next COBOL statement executed is ACCEPT INPUT-DATA FROM CONSOLE, the following message appears in the Debug Tool Log window:
CONSOLE : IGZ0000I AWAITING REPLY. The program is waiting for input from CONSOLE. Use the INPUT command to enter 114 characters for the intercepted fixed-format file.
Continue execution by replying to the input request by entering the following Debug Tool command:
INPUT some data ;
You can display the storage for a variable by using the LIST STORAGE command. For example, to display the storage for the first 12 characters of BUFFER-DATA enter:
LIST STORAGE(BUFFER-DATA,12)
You can also display only a section of the data. For example, to display the storage that starts at offset 4 for a length of 6 characters, enter:
LIST STORAGE(BUFFER-DATA,4,6)
Refer to the following topics for more information related to the material discussed in this topic.
Often when you get close to a programming error, you want to know how you got into that situation, and especially what the traceback of calling routines is. To get this information, issue the command:
LIST CALLS ;
Example: sample COBOL program for debugging
For example, if you run the COBCALC example with the commands:
AT APPEARANCE COBVALU AT ENTRY COBVALU; GO; GO; LIST CALLS;
the Log window contains something like:
AT APPEARANCE COBVALU
AT ENTRY COBVALU ;
GO ;
GO ;
LIST CALLS ;
At ENTRY in COBOL program COBVALU.
From LINE 67.1 in COBOL program COBCALC.which shows the traceback of callers.
To trace a program showing the entry and exit points without requiring any changes to the program, place the following Debug Tool commands in a file or data set and USE them when Debug Tool initially displays your program. Assuming you have a PDS member, USERID.DT.COMMANDS(COBCALC), that contains the following Debug Tool commands:
* Commands in a COBOL USE file must be coded in columns 8-72. * If necessary, commands can be continued by coding a '-' in * column 7 of the continuation line. 01 LEVEL PIC 99 USAGE COMP; MOVE 1 TO LEVEL; AT ENTRY * PERFORM; COMPUTE LEVEL = LEVEL + 1; LIST ( "Entry:", LEVEL, %CU); GO; END-PERFORM; AT EXIT * PERFORM; LIST ( "Exit:", LEVEL); COMPUTE LEVEL = LEVEL - 1; GO; END-PERFORM;
You can use this file as the source of commands to Debug Tool by entering the following command:
USE USERID.DT.COMMANDS(COBCALC)
If, after executing the USE file, you run COBCALC, the following trace (or similar) is displayed in the Log window:
ENTRY: LEVEL = 00002 %CU = COBCALC ENTRY: LEVEL = 00003 %CU = COBLOAN EXIT: LEVEL = 00003 ENTRY: LEVEL = 00003 %CU = COBVALU EXIT: LEVEL = 00003 ENTRY: LEVEL = 00003 %CU = COBVALU EXIT: LEVEL = 00003 EXIT: LEVEL = 00002
If you do not want to create the USE file, you can enter the commands through the command line, and the same effect is achieved.
To generate a trace showing the names of paragraphs through which execution has passed, the Debug Tool commands shown in the following example can be used. You can either enter the commands from the Debug Tool command line or place the commands in a file or data set.
Example: sample COBOL program for debugging
Assume you have a PDS member, USERID.DT.COMMANDS(COBCALC2), that contains the following Debug Tool commands.
* COMMANDS IN A COBOL USE FILE MUST BE CODED IN COLUMNS 8-72. * IF NECESSARY, COMMANDS CAN BE CONTINUED BY CODING A '-' IN * COLUMN 7 OF THE CONTINUATION LINE. AT GLOBAL LABEL PERFORM; LIST LINES %LINE; GO; END-PERFORM;
When Debug Tool initially displays your program, enter the following command:
USE USERID.DT.COMMANDS(COBCALC2)
After executing the USE file, you can run COBCALC and the following trace (or similar) is displayed in the Log window:
42 ACCEPT-INPUT.
59 CALCULATE-LOAN.
42 ACCEPT-INPUT.
66 CALCULATE-VALUE.
64 GET-AMOUNTS.
64 GET-AMOUNTS.
64 GET-AMOUNTS.
64 GET-AMOUNTS.
64 GET-AMOUNTS.
42 ACCEPT-INPUT.
66 CALCULATE-VALUE.
64 GET-AMOUNTS.
64 GET-AMOUNTS.
64 GET-AMOUNTS.
64 GET-AMOUNTS.
64 GET-AMOUNTS.
42 ACCEPT-INPUT.
During program run time, some storage might unexpectedly change its value and you want to find out when and where this happened. Consider this example where the program changes more than the caller expects it to change.
05 FIELD-1 OCCURS 2 TIMES
PIC X(8).
05 FIELD-2 PIC X(8).
PROCEDURE DIVISION.
* ( An invalid index value is set )
MOVE 3 TO PTR.
MOVE "TOO MUCH" TO FIELD-1( PTR ).Find the address of FIELD-2 with the command:
DESCRIBE ATTRIBUTES FIELD-2
Suppose the result is X'0000F559'. To set a breakpoint that watches for a change in storage values starting at that address for the next 8 bytes, issue the command:
AT CHANGE %STORAGE(H'0000F559',8)
When the program runs, Debug Tool halts if the value in this storage changes.
Calling an undefined program is a severe error. If you have developed a main program that calls a subprogram that doesn’t exist, you can cause Debug Tool to halt just before such a call. For example, if the subprogram NOTYET doesn't exist, you can set the breakpoint:
AT CALL (NOTYET)
When Debug Tool stops at this breakpoint, you can bypass the CALL by entering the GO BYPASS command. This allows you to continue your debug session without raising a condition.