I'm not sure that I should admit this, but most of the time I really enjoy an opportunity (when the timing is right, of course) to go digging into a dump. In my earlier days I saw it as a challenge. Sometime after that it became a matter of pride that I could work my way through a dump when many of the other programmers around me couldn't (or wouldn't).
Anyway, RPG being a bit unique as a programming language, it also has some unique approaches to using a dump to resolve a bad bug. First, where most programs use a higher number register (usually Register 12) as a base register, the key to an RPG dump is Register 3. When a condition exists that causes an RPG program to terminate abnormally, for example - a sequence error in an input file, the program will terminate with a User Abend (numbers in the range of 0040 to 0064 are common). Some of these are listed in the abend list here on my site. But just knowing why the abend occured may not be enough to resolve the problem.
The most frequent indicator of why an RPG program abended will be found by analyzing the Indicators that were on at the time of the abend, specifically the Halt Indicators. Following the RPG source listing In the compiler output is a symbol table. Here is the one from Example program three:
SYMBOL TABLES RESULTING INDICATORS ADDRESS RI ADDRESS RI ADDRESS RI ADDRESS RI ADDRESS RI ADDRESS RI ADDRESS RI 000004 U1 000005 U2 000006 U3 000007 U4 000008 U5 000009 U6 00000A U7 00000B U8 000011 OF 000014 1P 000015 LR 000016 00 000017 01 000018 02 00002A 20 00002B 21 00007A L0 000085 H0 000086 H1 000087 H2 000088 H3 000089 H4 00008A H5 00008B H6 00008C H7 00008D H8 00008E H9 FIELD NAMES ADDRESS FIELD ADDRESS FIELD ADDRESS FIELD ADDRESS FIELD ADDRESS FIELD 000127 IDENTA 00012E NAME 000151 ADDR1 000174 IDENTB 00017B ADDR2 00019E GENDER 00019F PHONE 0001A5 BDATE 0001AA MAJOR 0001AD Z5 0001B0 B40 0001D8 CACNT 0001DA CBCNT 0001DC PREVA 0001E3 MISSB 0001EA KEYH 0001F1 ADDCNT |
The table gives the offset address (in hexadecimal) for all the Indicators and Fields used in the program. Adding the address to the contents of Register 3 yields the absolute location in the dump to find the Indicator or Field contents at the time of the dump.
Of particular interest is H0, which is always located at x'85'. If H0 is on, there is a table (the H0 analysis table) that may give additional information about the abend. The contents of this table are found by adding Register 3 to x'11C', x'120', x'121', and x'122'. Obviously the last three are adjacent single byte fields, so it is really only necessary to compute the first address. The first address, if applicable, points to either an Input Output Request Block (IORB) or a Define The File (DTF) table. The possible meanings that can be ascribed to the three reason codes are:
Condition that turned H0 on | x'11C' | x'120' | x'121' | x'122' |
Initialized on or turned on by programmer | N/A | 00 | 00 | 00 |
Invalid chaining request | N/A | 02 | N/A | N/A |
Undefined record type | IORB | 10 | N/A | N/A |
Collating sequence error (matching records) | N/A | 04 | N/A | N/A |
Record sequence error | N/A | 08 | N/A | N/A |
DAM (record not found) | DTF | N/A | 80 | N/A |
DAM (data check) | DTF | N/A | 40 | N/A |
DAM (wrong length record) | DTF | N/A | 20 | N/A |
ISAM (invalid key length) | IORB | N/A | N/A | FF |
ISAM (DASD error) | DTF | N/A | N/A | 80 |
ISAM (wrong length record) | DTF | N/A | N/A | 40 |
ISAM (illegal End Of File within limits) | DTF | N/A | N/A | 20 |
ISAM Load (prime data area full) | DTF | N/A | N/A | 20 |
ISAM Load (master index full) | DTF | N/A | N/A | 08 |
ISAM (duplicate record) | DTF | N/A | N/A | 04 |
ISAM Load (sequence error) | DTF | N/A | N/A | 02 |
ISAM Load (overflow area full) | DTF | N/A | N/A | 02 |
ISAM (no record found) | DTF | N/A | N/A | 10 |
ISAM Load (cylinder index full) | DTF | N/A | N/A | 10 |
ISAM Retrieve (illegal ID specified) | DTF | N/A | N/A | 08 |
ISAM Retrieve (record retrieved from overflow area) | DTF | N/A | N/A | 01 |
The address listed in the Memory Map for Input Output Request Blocks Pointer, when adjusted by the addition of the contents of Register 3, points to a table of Input/Output information about the files defined in the RPG program which abended. Each thirty-two byte entry in the table has the following format:
Displacement | Contents |
0 | address of record buffer |
4 | address of parameter list for DAM or ISAM |
8 | record length |
10 | line counter value |
12 | line counter info (x'11' = line counter present, x'EE' error in line counter routine |
13 | file number |
14 | action type (x'00' = read, x'02' = write, x'04' = stacker select |
15 | skip before or stacker number |
16 | space before |
17 | skip after |
18 | space after |
19 | overflow or end of file switch (x'00' = off, x'11' = printer overflow, x'22' end of file or end of extents, x'33' end of ISFMS limits |
20 | overflow switch two |
21 | sense overflow |
22 | ISAM with limits |
23 | first pass switch |
24 | file type |
25 | stacker select codes for device assigned to the file |
27 | record read from ISAM file (x'11' = record read, x'00' = record not read) |
28 | SETL switch (x'FF' = SETL or SETFL have been executed, x'00' = ESETL or ENDFL have been executed |
29 | ISAM key length |
30 | ISAM key location within data record |
When tables are used, the table names can be found in the field-names section of the Symbol Table. Each table name will have an associated hexadecimal address. By adjusting this address by the addition of the contents of Register 3, the table holding area can be found. Initially, this holding area specifies the contents of the first table entry. After a table LOKUP operation, the holding area will contain the contents of the last table entry found.
The actual table in core can be found by use of a sixteen byte table linkage field. The table linkage field is found by subtracting x'10' from the address of the table holding area. The starting address of the table data is located in bytes five through eight of the table linkage field. Bytes nine through twelve contain the address of the byte following the table. The work address is found in bytes thirteen through sixteen. Initially, this address contains hexadecimal zeros, but after a table LOKUP operation it contains the address of the last table element found.
Although not an exhaustive treatment of RPG dump analysis, this should be enough information to steer you to solving the majority of program problems.
This page was last updated on January 17, 2015.