technical: How to Check If You Have The Right Source
Confirming that you have the right source code used to create a load module is a problem too often encountered. Ideally source code management software such as CA Endevor will do this for us, connecting source to modules. However sometimes this isn't an option. So how can you confirm that your source and modules correspond?
There's good news, and there's bad news. The bad news is that we can't do this. The good news is that we can get close. Here's how.
Dates
The first step is to compare the dates of the source and module. So if you have a module compiled on 01-Jan-2015, and source last saved on 01-Jan-2015, that's a good sign. The date source code was last saved can often be found in the DSLIST of the PDS holding the source code.
BROWSE DSTEP.SOURCE Row 00001 of 0001
Command ===> Scroll ===> CSR
Name Prompt Size Created Changed ID
_________ COBOL3 45 2014/02/25 2014/02/25 22:08:50 DSTEP
This gives you the date each PDS was created and changed. In our case the member COBOL3 was last updated in 25-Feb-2014. If you're lucky enough to have your source code in SCM, then the SCM features will show this to you. However the date a source member was last saved isn't a guaranteed value for the date the source was last updated. The member may have been copied in from somewhere else, or saved with no changes. Another option is to look at the program source. Often programmers will include the date source was updated in comments.
The load module is a bit more difficult. Unless you're a systems programmer writing exits, most code will be application code. When compiled, the final load module will include the application module, and several other modules automatically. For example, COBOL, C/C++ and PL/I load modules always include Language Environment modules, SAS/C load modules SAS/C modules, and programs accessing CICS or DB2 some CICS or DB2 modules. You may also find some of your own included modules. So we need to isolate our program module from the rest in the load module.
Our weapon of choice is the IBM supplied batch utility AMBLIST. Run AMBLIST with the SYSIN
LISTIDR MEMBER=module
This will list IDR data for this member. IDR data can be thought of as notes for a module. Almost all compilers include information about the date it was compiled and the compiler. Here's some example output:
---------------------------------------------------------------------
THIS LOAD MODULE WAS PRODUCED BY LINKAGE EDITOR 5695PMB01
---------------------------------------------------------------------
CSECT TRANSLATOR VR.MD YR/DY
COBOL3 5655S7100 41.00 2014/056
IGZCBSO 569623400 01.04 2004/068
PL/X-390 02.02 2004/068
CEESG005 569623400 01.04 2004/068
PL/X-390 02.02 2004/068
CEESTART 569623400 01.04 2004/072
CEEBLLST 569623400 01.04 2004/072
CEEBTRM 569623400 01.04 2004/072
CEEBETBL 569623400 01.04 2004/072
CEEBPUBT 569623400 01.04 2004/072
CEEBINT 569623400 01.04 2004/071
PL/X-390 02.01 2004/071
CEEARLU 569623400 01.04 2004/071
PL/X-390 02.01 2004/072
CEEBPIRA 569623400 01.04 2004/072
PL/X-390 02.01 2004/072
CEECPYRT 569623400 01.04 2004/072
PL/X-390 02.01 2004/072
We can see that there are a lot of modules in our load module. The ones starting with CEE are Language Environment modules, IGZ Enterprise COBOL modules. Our program COBOL3 is at the top. It was compiled on day 056 in 2014: 25-Feb-2014. This is the same day as our source. So there's a good chance we have a matching module and source.
Products like IBM FileManager, IBM Debug Tool, or Serena StarTool DA show this information online without needing a batch AMBLIST job.
Module Size
Another possibility is to recompile our source code, and compare module sizes. We could even do a byte-by-byte comparison of the two modules.
Recompiling is a bit more difficult, as we need to recompile our source in exactly the same way: the exact same compiler and version. If you compile a program with the COBOL II compiler and Enterprise COBOL compiler, the output will be different. Even different versions of the same compiler can product different modules. So the first thing is to find out which compiler was used. Our IDRDATA can help again. In the above data, our module COBOL3 was compiled using version 41 of 5655S7100. This last number is the IBM product code: 5655-S71 with two zeroes at the end: IBM Enterprise COBOL 4.1. In our article Find Out More About Your Load Module, we discuss load modules in some more detail.
We also need to compile with exactly the same COBOL compile options. Getting compiler options can be difficult. If you have IBM Debug Tool, you can use the Load Module Analyzer to get compiler options for some compilers:
5655-W70 Debug Tool Version 12 Release 1.2 Load Module Analyzer
Load Module DZS.LOAD(CICSPGM) AMODE(31),RMODE(ANY)
CSECT Offset Len/Ent Program-ID Trn-Date Program-Descriptio
CICPGM1 0 A40 5655W32 2015/01/07 Enterprise COBOL f
LEINFO=(COBOL,V05R01M01 2015/01/07 02:52:
COMPOPTS: ADV AFP(VOLATILE)
NOAWO NOBLOCK0 NOCICS
DBCS NODECK DISPSIGN(COMPAT)
NODYNAM NOEXPORTALL NOFASTSRT
MAP NOMDECK NONAME
NOOFFSET NOOPTFILE OPTIMIZE(0)
RENT RMODE(ANY) SEQUENCE
SQLCCSID NOSSRANGE NOSTGOPT
TRUNC(STD) NOVBREF NOWORD
Other tools such as Serena StarTool FDM, Prince Load Analyzer, Edge Portfolio Analyzer and GSF LOADXREF can also help. The CBT website also has a sample program for determining compile options of some older COBOL compilers in file 552.
From here we compile our source into a different library, and compare the load modules. However we need to only compare our module. We ignore the Language Environment, CICS and other modules as they may have changed: few sites have access to older versions of Language Environment or similar modules. Again, AMBLIST comes to the rescue. Using the LISTLOAD OUTPUT=MODLIST, we can get a listing of our module:
RECORD# 1 TYPE 20 - CESD ESDID 1 ESD SIZE 240
CESD# SYMBOL TYPE ADDRESS R/R/A ID/LENGTH(DEC)
1 COBOL3 00(SD) 000000 07 1672
2 IGZCBSO 00(SD) 000778 06 1392
3 CEESTART 00(SD) 0006C8 07 176
4 CEEBETBL 00(SD) 0006A0 07 40
5 CEESG005 00(SD) 000688 07 24
6 CEEBXITA 0A(WX) 000000
7 CEEBINT 00(SD) 0012D0 07 8
8 CEEBLLST 00(SD) 001270 07 92
9 CEEUOPT 0A(WX) 000000
10 CEEBTRM 00(SD) 0011C8 07 164
11 CEEBPUBT 00(SD) 001158 07 112
12 IEWBLIT 0A(WX) 000000
13 CEEMAIN 0A(WX) 000000
14 CEEFMAIN 0A(WX) 000000
15 CEEROOTA 0A(WX) 000000
RECORD# 2 TYPE 20 - CESD ESDID 16 ESD SIZE 240
CESD# SYMBOL TYPE ADDRESS R/R/A ID/LENGTH(DEC)
16 CEEROOTD 0A(WX) 000000
17 CEEINT 03(LR) 000D98 06 21
The first records of a traditional load module are the CESD records: an index to the modules in a load module. Our COBOL3 is at the top, and is 1672 bytes in length. So if the new and old modules are the same length, the chances are that they're the same module. You can also compare the modules – AMBLIST can dump out the module contents. IBM Debug Tool also includes a load module comparison utility.
Analyse the Load Module
A final possibility is to look more closely at the load module, and compare it to your source. This sounds crazy, as they look nothing alike. However there is information to be found. It won't give us everything, but can be used when choosing between different source code versions.
For example, using AMBLIST, you can get a list of all modules in a load module, including any included modules. Suppose we have one source that includes one module, and a second that includes two. Or one that includes MODA, and another that includes MODB. Using AMBLIST, we can see the included modules, and instantly determine which source we need.
Constants are another option. We can find constant values such as strings in a load module by browsing it. Consider the following output from a load module browse:
BROWSE DSTEP.LOADLIB(COBOL3) Line 00000000 Col 301 380
Command ===> Scroll ===> CSR
******************************** Top of Data ****************************
..0...Ü............INPUT NAME DEFINED: DEFAULT NAME INPUTCOBOL3 STARTINGC
******************************* Bottom of Data **************************
And the corresponding COBOL source:
PROCEDURE DIVISION.
DISPLAY "COBOL3 STARTING"
IF INPUT-NAME = " "
MOVE "(NO NAME)" TO INPUT-NAME
DISPLAY "NO INPUT NAME"
DISPLAY "DEFAULT NAME INPUT"
ELSE
DISPLAY "INPUT NAME DEFINED: " INPUT-NAME
MOVE "(HAVE NAME)" TO INPUT-NAME
END-IF
MOVE "(END NAME)" TO INPUT-NAME
DISPLAY "COBOL3 ENDING".
GOBACK.
EXIT.
Constants we use in our COBOL program are in clear text in our load module. Again, if we have two versions of a module: one with messages in English, another in Spanish, then a simple browse can determine which corresponds to a load module.
Other load module attributes can be similarly used, such as AMODE and RMODE, or even compile options.
Conclusion
The fact is that it is almost impossible to confirm that a particular source code was used to generate a load module. The only sure way is to recompile the source, and compare the resulting module with the original. However the source must be recompiled with the same compiler and version, compiler options, and copybooks and includes. In many cases this isn't an option. Outside of this, there are several ways to get a good estimate by analysing the load module and its corresponding source.
David Stephens
|