LongEx Mainframe Quarterly - May 2014
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. DatesThe 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 SizeAnother 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 ModuleA 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. ConclusionThe 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. |