コンパイルリストとリンクリストからエラー箇所を探る
- 1 概要
-
プログラムエラーが発生したときに、エラー情報として8桁の数字が表示されます。
例えば「ADR=00005093C」と表示します。
コンパイルリストとリンクリストがあれば、この8桁の数字をもとにエラーの起きた命令を探し出すことができます。
- 2 例題で探してみる
-
まずサンプルとして以下のようなプログラムを用意しました。3つのCOBOLプログラムを1つにリンクしてロードモジュールを作ってみます。
ちなみに何の役にも立たない上にバグっています。
CHILD2の12行目でGR01にACCEPTしていますが、GR01は集団項目なので英文字や記号も入力できます。
14行目でI1とI2を足してI3に入れていますが、GR01で記号を入力していたらアウトです。数字ではないのでここでプログラムエラーになるはず。000001 IDENTIFICATION DIVISION. 000002 PROGRAM-ID. PERENT. 000003 ENVIRONMENT DIVISION. 000004 CONFIGURATION SECTION. 000005 DATA DIVISION. 000006 WORKING-STORAGE SECTION. 000007 01 ENDMSG PIC X(5). 000008 PROCEDURE DIVISION. 000009 MAIN-RTN. 000010 DISPLAY "CHILD1 START". 000011 CALL "CHILD1". 000012 DISPLAY "CHILD1 END". 000013 DISPLAY "CHILD2 START". 000014 CALL "CHILD2". 000015 DISPLAY "CHILD2 END". 000016 ACCEPT ENDMSG. 000017 STOP RUN.
000001 IDENTIFICATION DIVISION. 000002 PROGRAM-ID. CHILD1. 000003 ENVIRONMENT DIVISION. 000004 DATA DIVISION. 000005 WORKING-STORAGE SECTION. 000006 01 CH001 PIC X(1). 000007 PROCEDURE DIVISION. 000008 CH1-MAIN. 000009 DISPLAY "ENTER NUMBER,PLEASE". 000010 EXIT PROGRAM.
000001 IDENTIFICATION DIVISION. 000002 PROGRAM-ID. CHILD2. 000003 ENVIRONMENT DIVISION. 000004 DATA DIVISION. 000005 WORKING-STORAGE SECTION. 000006 01 GR01. 000007 05 I1 PIC 9(02) VALUE ZERO. 000008 05 I2 PIC 9(02) VALUE ZERO. 000009 01 I3 PIC 9(03). 000010 PROCEDURE DIVISION. 000011 CH2-MAIN. 000012 ACCEPT GR01. 000013 DISPLAY GR01 " : " I1 " : " I2 " : ". 000014 COMPUTE I3 = I1 + I2. 000015 DISPLAY I3. 000016 EXIT PROGRAM.
3つのプログラムをコンパイルして、リンクします。下がリンクした結果出力されたリスト(の一部)です。使用するところだけ載せています。
「INC (PERENT,CHILD1,CHILD2)」となっているように3つのプログラムをリンクしています。「LMN = PER1」となっているように、作ったロードモジュールの名前はPER1です。
USER CU DEVICE; CUD = MSD001 USER CU FILE NAME; CUF = USERCUL USER CU DEVICE; CUD = 999 USER CU LIBRARY DEVICE; UCD = MSD001 USER CU LIBRARY FILE NAME; UCF = USERCUL SYSTEM CU LIBRARY DEVICE; SCD = MSD SYSTEM CU LIBRARY FILE NAME; SCF = SYS@CUL LOAD MODULE DEVICE; LMD = MSD001 LOAD MODULE FILE NAME; LMF = USERLML LOAD MODULE NAME; LMN = PER1 OUTPUT MODE; MOD = REPLACE RUN; RUN = NO LIST; LST = ALL PRINT DEVICE; PRD = SYSTEMSPOOL WORK DEVICE; WKD = TEMPORARY OVERLAY STRUCTURE; OVR = SIMPLE FORTRAN UNIT NO; UNT = NO OPTIONAL FUNCTION; OPT = NO INC (PERENT,CHILD1,CHILD2) END MAP LIST RESIDENT PART ******************************* *** DATA PART ****************************** ******** SEGMENT 0000 (0004) SIZE = 00001928 ( 6440) FILE CU-NAME REV. COMPILED ATR LANG SIZE FROM -TO ADDR EXT/COMM SIZE SEG. STAC 000002A0 ( 672) 00040100-0004039F SCF LNK@OV 0018 62/03/14 DATA SYS 0000001A ( 26) 000403A0-000403B9 LNK@OVSG 000403B4 SCF SYS@ID V101 94/08/11 S006 SYS 00000002 ( 2) 000403BC-000403BD SCF SYS@ID V101 94/08/11 S001 SYS 00000634 ( 1588) 000403C0-000409F3 SYS@IDPB 000405E4 CUF1 PERENT 0003 26/05/26 S100 CBL 000000AC ( 172) 000409F4-00040A9F 0005099C COB@4APR 0001 000509FC COB@0VDP 0001 00050878 CHILD1 0001 000508F0 CHILD2 0001 00050BC8 COB@0UAP 0001 00050D90 COB@0XSR 0001 00050DE8 COB@0BEP 0001 CUF1 CHILD1 0002 26/05/26 S100 CBL 00000064 ( 100) 00040AA0-00040B03 0005099C COB@4APR 0001 000509FC COB@0VDP 0001 00050DE8 COB@0BEP 0001 00050D90 COB@0XSR 0001 CUF1 CHILD2 0002 26/05/26 S100 CBL 0000009C ( 156) 00040B04-00040B9F 0005099C COB@4APR 0001 00050BC8 COB@0UAP 0001 000509FC COB@0VDP 0001 00050DE8 COB@0BEP 0001 00050D90 COB@0XSR 0001 SCF SYS@0V 0022 01/03/16 DATA SYS 00000074 ( 116) 00040BA0-00040C13 00050CB0 COB@9AAB 0001 00050F0C COB@9WWK 0001 SCF SYS@0U 0006 87/04/21 DATA SYS 0000004C ( 76) 00040C14-00040C5F 00050CB0 COB@9AAB 0001 00050F0C COB@9WWK 0001 SCF SYS@9A 0005 91/05/21 DATA SYS 00000074 ( 116) 00040C60-00040CD3 COB@9ACM 00040C60 COB@9ACC 00040C60 COB@9ASV 00040C70 COB@9AAB 00040CB0 COB@9ADB 00040CC0 SCF SYS@IT 0001 84/07/29 DATA SYS 00000010 ( 16) 00040CD4-00040CE3 SCF SYS@9W 0006 93/03/08 DATA SYS 00000B28 ( 2856) 00040CE4-0004180B COB@9WDT 00040CE4 COB@9WWK 00040F0C COB@9WPS 0004170C SCF SYS@9G 0003 94/08/09 DATA SYS 0000011C ( 284) 0004180C-00041927 COB@9GEP 0004180C COB@9GCA 00041910 COB@9GDB 00041914 *** PROC PART ****************************** ******** SEGMENT 0001 (0005) SIZE = 00000E74 ( 3700) FILE CU-NAME REV. COMPILED ATR LANG SIZE FROM -TO ADDR EXT/COMM SIZE SEG. SCF LNK@OV 0018 62/03/14 PROC SYS 000000AA ( 170) 00050000-000500A9 LNK@OVCA 00050026 LNK@OVLD 00050024 LNK@OVBC 00050000 LNK@OVBL 00050012 LNK@OVIT 00050070 SCF SYS@ID V101 94/08/11 S003 SYS 000006FC ( 1788) 000500AC-000507A7 SYS@ID 000500AC SYS@IDPT 0005061A CUF1 PERENT 0003 26/05/26 S000 CBl 000000D0 ( 208) 000507A8-00050877 PERENT 000507A8 CUF1 CHILD1 0002 26/05/26 S000 CBl 00000078 ( 120) 00050878-000508EF CHILD1 00050878 CUF1 CHILD2 0002 26/05/26 S000 CBl 000000AA ( 170) 000508F0-00050999 CHILD2 000508F0 SCF SYS@4A 0004 84/07/28 PROC SYS 0000005E ( 94) 0005099C-000509F9 COB@4APR 0005099C 00040CB0 COB@9AAB 0000 00050E34 SYS@ITEM 0001 00040F0C COB@9WWK 0000 00040C60 COB@9ACM 0000 SCF SYS@0V 0022 01/03/16 PROC SYS 000001CC ( 460) 000509FC-00050B COB@0VDP 000509FC SCF SYS@0U 0006 87/04/21 PROC SYS 000001C6 ( 454) 00050BC8-00050D COB@0UAP 00050BC8 SCF SYS@0X 0001 92/03/30 PROC SYS 00000056 ( 86) 00050D90-00050D COB@0XSR 00050D90 00040CB0 COB@9AAB 0000 00041910 COB@9GCA 0000 00040C60 COB@9ACM 0000 SCF SYS@0B 0003 87/04/20 PROC SYS 0000004A ( 74) 00050DE8-00050E COB@0BEP 00050DE8 00040CB0 COB@9AAB 0000 00050E34 SYS@ITEM 0001 SCF SYS@IT 0001 84/07/29 PROC SYS 0000003E ( 62) 00050E34-00050E SYS@ITEN 00050E34
さて、実行してみましょう。ロードモジュール名はPER1です。RUNコマンドでPER1を実行します。
4桁の入力のところで記号を入力します。例えば「!"#$」と入力すると予想通りエラーとなりました。
「E M0021: (PRG=PER1 ,ADR=0005093C) 不正十進数エラー」とエラーメッセージが表示されました。
最初の「E M0021:」の部分は不正十進数エラーのエラーコードです。NEC公式の「システム操作法ガイドブック<メッセージ編>を見ると次のように書いてあります。
E M0021: (PRG=pppppp, ADR=aaaaaaaa) 不正十進エラー [説明]10進演算命令にて不正な符号あるいは数字以外のデータが検出されました。 pppppp・・・不正十進数の演算を実行したプログラム名 aaaaaaaa・・・不正十進数エラーが発生した演算命令の6番地進んだ番地 〜後略〜
次の「PER1」はエラーとなったロードモジュールの名前です。今PER1を実行したので、その名前が表示されています。
次の「ADR=0005093C」です。これはアドレスです。「演算命令」なので命令の場所を示しています。つまりエラーとなった演算命令の場所がわかります。だだしこれでは具体的にどの命令でエラーになったのかはわかりません。このままでは単なる数字の羅列です。これからエラーになった命令を探します。
最初の4桁はLSA番号と呼ばれています。この場合は「0005」です。
ここでリンクリストの出番です。
リンクリストの「MAP LIST」を見てください。命令なので「PROC PART」を探してください。 次の行に「SEGMENT 0001 (0005)」と書いてあると思います。ここの括弧内に書いてある番号と「0005」が一致するものを探します。今回は「0005」ですが、もし「0006」だったら(0006)となっているところを探します。「FROM -TO」となっている列を見てください「0005xxxx-0005xxxx」となっている行がたくさんあります。これはプログラムが占めている領域を示します。 例えばCU-NAMEがLNK@OVの行を見ると「00050000-000500A9」となっています。00050000から000500A9の範囲にLNK@OVの命令が書かれていることを示します。
PERENTは「000507A8-00050877」です。PERENTの命令は000507A8から00050877の範囲に書かれています、ということです。
CHILD1は「00050878-000508EF」、CHILD2は「000508F0-00050999」となっています。さて、PER1でエラーとなったのは、「ADR=0005093C」ですね。
0005093Cを含むプログラムを探します。CHILD2は000508F0から00050999の範囲です。0005093CはCHILD2の範囲の中に含まれます。
つまりエラーとなった演算命令を含むプログラムはCHILD2であることがわかります。エラーになったアドレスは「ADR=0005093C」です。CHILD2の先頭のアドレスは000508F0です。
0005093C − 000508F0 = 4C。CHILD2の先頭から4Cの位置にある命令がエラーになった命令です。それでは次にCHILD2のコンパイルリストを見てみます。
PARAMETER LIST SOURCE UNIT DEVICE; SUD = MSD001 SOURCE UNIT FILE NAME; SUF = USERSUL COPY LIBRARY DEVICE; LBD = MSD COPY LIBRARY FILE NAME; LBF = SYS@SUL COMPILE UNIT DEVICE; CUD = MSD001 COMPILE UNIT FILE NAME; CUF = USERCUL WORK DEVICE; WKD = TEMPORARY WORK FILE SIZE; WSZ = 01000 PRINT DEVICE; PRD = SYSTEMSPOOL PROGRAM NAME; PRG = CHILD2 COMPILE UNIT OUTPUT MODE; MOD = REPLACE CU CHARACTER CODE; COD = SOURCE LIST; LST = ALL HORINZONTAL ADDRESS TAB CODE; HAT = NO DEBUG MODE; DBG = SOURCE OPTIONAL FUNCTION; OPT = NO NEXT; NXT = NO LINE SEQ-NO ***** SOURCE PROGRAM LIST ***** 1 000001 IDENTIFICATION DIVISION. 2 000002 PROGRAM-ID. CHILD2. 3 000003 ENVIRONMENT DIVISION. 4 000004 DATA DIVISION. 5 000005 WORKING-STORAGE SECTION. 6 000006 01 GR01. 7 000007 05 I1 PIC 9(02) VALUE ZERO. 8 000008 05 I2 PIC 9(02) VALUE ZERO. 9 000009 01 I3 PIC 9(03). 10 000010 PROCEDURE DIVISION. 11 000011 CH2-MAIN. 12 000012 ACCEPT GR01. 13 000013 DISPLAY GR01 " : " I1 " : " I2 " : ". 14 000014 COMPUTE I3 = I1 + I2. 15 000015 DISPLAY I3. 16 000016 EXIT PROGRAM. LINE LEVEL SYMBOL PICTURE/COMMENT USAGE ADDRESS LENGTH * WORKING-STORAGE SECTION * 6 01 GR01 X(00004) DISPLAY D100 0040( 64) 0004( 4) 7 05 I1 9(02) DISPLAY D100 0040( 64) 0002( 2) 8 05 I2 9(02) DISPLAY D100 0042( 66) 0002( 2) 9 01 I3 9(03) DISPLAY D100 0044( 68) 0003( 3) * PROCEDURE NAME * 11 CH2-MAIN *** SYMBOL *** DEF.NO REF.NO ***** CROSS REFERENCE LIST ***** CH2-MAIN 11 COMPLETION-CODE S.R. FUNCTION-KEY S.R. GR01 6 12 13 I1 7 13 14 I2 8 13 14 I3 9 14 15 PROGRAM-ID S.R. RDB-STATUS S.R. LINE ADDR LINE ADDR LINE ADDR LINE ADDR LINE ADDR LINE ADDR LINE ADDR LINE ADDR LINE ADDR LINE ADDR SECTION 00 (PROC#00) 10 0000 11 002A 12 002A 13 0038 14 0046 15 005C 16 006A *** END PROCEDURE MAP LIST *** **** PROGRAM MEMORY SIZE LIST **** DATA PART DATA#100 009C (00156) PROCEDURE PART SECTION 00 (PROC#00) (PERMANENT ) 00AA (00170) MAXIMUM MEMORY SIZE DATA PART 00009C (00000156) PROCEDURE PART 0000AA (00000170) **** ERROR SUMMARY LIST **** 00000 FATAL ERRORS 00000 WARNINGS 00000 DELETED WARNINGS SUCCESSFULLY COMPILED
コンパイルリストの真ん中あたりに「LINE ADDR LINE ADDR・・・」となっている行がありますよね。 例えば一番最初の「10 0000」となっていますが、この10は命令部の最初の「10 000010 PROCEDURE DIVISION.」の10に対応します。 次の「11 002A」は「11 000011 CH2-MAIN.」の10に対応します。
「PROCEDURE DIVISION」の命令は「0000」の位置から始まっていることを示しています。次の「CH2-MAIN.」の命令は「002A」から始まっていることを示しています。「PROCEDURE DIVISION」の命令は0000から0029までの間にあります。
このように見ていくと、4Cは「14 0046」と「15 005C」の間なので、14の命令の中にあります。
14の命令を見ると、「14 000014 COMPUTE I3 = I1 + I2.」です。演算命令ですね。この命令で不正十進数エラーになっていることがわかります。