ダンプリスト解析入門⑩
ダンプリスト解析入門⑩:プログラム割込みによるABENDダンプ解析サンプル
シリーズの最後に、簡単なプログラムを使ってABENDダンプの解析を行ってみます。アセンブラー・プログラムで起こりがちなS0C4 ABEND(記憶保護例外)です。故意にプログラムで0番地などに書き込むのは現実的ではないので、実践でもありがちな例を使ってみます。
サンプル・プログラムの内容は、STCK命令で得たCPUの現時刻をYYYYMMDD HHMMSS形式に変換するものです。実際の変換にはMVSのAPIサービスであるCONVSTCKマクロを使用します。
サンプル・プログラムのABENDによるダンプリスト(SYSUDUMP)とプログラムのアセンブル結果
ダンプリスト
ジョブログ上の徴候ダンプ ======================== IEA995I SYMPTOM DUMP OUTPUT 450 SYSTEM COMPLETION CODE=0C4 REASON CODE=00000004 TIME=10.53.05 SEQ=00032 CPU=0000 ASID=0020 PSW AT TIME OF ERROR 078D0000 80007FD6 ILC 6 INTC 04 ACTIVE LOAD MODULE ADDRESS=00007F18 OFFSET=000000BE NAME=TEMPNAM0 DATA AT PSW 00007FD0 - D20FE000 100C58D0 D00458E0 GR 0: 00000000 1: 00007F9C 2: 00000040 3: 009D29D4 4: 009D29B0 5: 009EC818 6: 00007FF0 7: FD000000 8: 009ECA10 9: 009ECAD8 A: 00000000 B: 009EC818 C: 00007F18 D: 80007F28 E: 00000006 F: 00000000 END OF SYMPTOM DUMP ダンプに出力されたレジスター内容 ================================ REGISTERS AT ENTRY TO ABEND FLOATING POINT REGISTER VALUES FPC 00000000 0-3 00000000 00000000 00000000 00000000 00000000 00000000 ・・・ 4-7 00000000 00000000 00000000 00000000 00000000 00000000 ・・・ 8-11 00000000 00000000 00000000 00000000 00000000 00000000 ・・・ 12-15 00000000 00000000 00000000 00000000 00000000 00000000 ・・・ GPR VALUES 0-3 00000000 00007F9C 00000040 009D29D4 4-7 009D29B0 009EC818 00007FF0 FD000000 8-11 009ECA10 009ECAD8 00000000 009EC818 12-15 00007F18 80007F28 00000006 00000000 ACCESS REGISTER VALUES 0-3 00000000 00000000 00000000 00000000 4-7 00000000 00000000 00000000 00000000 8-11 00000000 00000000 00000000 00000000 12-15 00000000 00000000 00000000 00000000 64-BIT GPR VALUES 0-3 00000000 00000000 00000000 00007F9C 00000000 00000040 ・・・ 4-7 00000000 009D29B0 00000000 009EC818 00000000 00007FF0 ・・・ 8-11 00000000 009ECA10 00000000 009ECAD8 00000000 00000000 ・・・ 12-15 00000000 00007F18 00000000 80007F28 00000000 00000006 ・・・ プログラム領域の内容 ==================== 00007F00 00000000 00000000 00000000 00000000 *................ 00007F10 00000000 00000000 90ECD00C 41C0F000 ..........}..{0.* 00007F20 18FD0700 4DD0C058 FFFFFFFF 00006F60 *....(}{.......?- 00007F30 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF ................* 00007F40 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF *................ 00007F50 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF ................* 00007F60 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF *................ 00007F70 50F0D004 50D0F008 B205C0D0 4160C0D8 &0}.&}0...{}.-{Q* 00007F80 51100000 4110C084 92031002 51E0C0D0 *......{dk....\{} 00007F90 D2071004 E00047F0 C0A00000 00000322 K...\..0{.......* 00007FA0 CB1EE954 98DD0000 01530548 62880000 *..Z.q........h.. 00007FB0 20130327 00000000 92221003 58E00010 ........k....\..* 00007FC0 58EE0304 58EE0130 B218E000 51E00006 *..........\..\.. 00007FD0 D20FE000 100C58D0 D00458E0 D00C980C K.\....}}..\}.q.* 00007FE0 D01447F0 E0000000 CB1EE954 98DD0000 *}..0\.....Z.q... 00007FF0 00000000 00000000 00000000 00000000 ................* ※画面上見やすくするため1行16バイトずつの表示に編集してあるが、 実際のダンプリストでは1行32バイトずつの表示となる。
アセンブル・リスト
000000 00000 000E8 4 MAINENTR CSECT , DEFINE CODE SECTION 5 MAINENTR AMODE 31 DEFINE DEFAULT AMODE 6 MAINENTR RMODE 24 DEFINE DEFAULT RMODE R:C 00000 7 USING *,12 DEFINE BASE REGISTER 000000 90EC D00C 0000C 8 STM 14,12,12(13) SAVE CALLER REGISTERS 000004 41C0 F000 00000 9 LA 12,0(,15) GR12 -> OUR 1ST BASE ADDRESS 000008 18FD 10 LR 15,13 SAVE CALLER SAVEAREA 00000A 0700 11 CNOP 0,4 INSURE FULL WORD BOUNDARY 00000C 4DD0 C058 00058 12 BAS 13,*+4+72 AROUND OUR SAVEAREA 000010 FFFFFFFFFFFFFFFF 13 DC 18F'-1' OUR GPR SAVEAREA 000058 50F0 D004 00004 14 ST 15,4(,13) SAVE CALLER SAVEAREA POINTER 00005C 50D0 F008 00008 15 ST 13,8(,15) SET BACK CHAIN FOR LINK TRACE 000060 B205 C0D0 000D0 30 STCK DOUBLE GET CURRENT CLOCK 000064 4160 C0D8 000D8 31 LA R6,EDITAREA 32 STCKCONV STCKVAL=DOUBLE, CONVERT TO YYYYMMDD/HHMMSS... + CONVVAL=R6, + DATETYPE=YYYYMMDD,TIMETYPE=DEC 33+* MACDATE 05/30/98 @L1C 000068 34+ DS 0H 000068 5110 0000 00000 35+ LAE 1,0(0,0) ZERO ACCESS REGISTER 1 00006C 4110 C084 00084 36+ LA 1,IHB0001K POINT TO PARAMETER LIST 000070 9203 1002 00002 37+ MVI 2(1),3 SET DATETYPE FLAGS IN PARM LIST 000074 51E0 C0D0 000D0 38+ LAE 14,DOUBLE ADDRESS OF STCKVAL 000078 D207 1004 E000 00004 00000 39+ MVC 4(8,1),0(14) MOVE STCKVAL INTO PARM LIST 00007E 47F0 C0A0 000A0 40+ B IHB0001A BRANCH AROUND LIST 000084 41+IHB0001K DS 0F 000084 0000 42+ DC FL2'0' 000086 00 43+ DC FL1'0' 000087 00 44+ DC FL1'0' 000088 0000000000000000 45+ DC 2F'0' 000090 0000000000000000 46+ DC 2F'0' 000098 0000000000000000 47+ DC 2F'0' 0000A0 48+IHB0001A DS 0H 0000A0 9222 1003 00003 49+ MVI 3(1),34 SET TIMETYPE FLAGS IN PLIST @L1M 0000A4 58E0 0010 00010 50+ L 14,16(0,0) CVT ADDRESS 0000A8 58EE 0304 00304 51+ L 14,772(14,0) SFT ADDRESS 0000AC 58EE 0130 00130 52+ L 14,304(14,0) LX/EX FOR SERVICE ROUTINE 0000B0 B218 E000 00000 53+ PC 0(14) 0000B4 51E0 0006 00006 54+ LAE 14,R6 ADDRESS OF CONVVAL 0000B8 D20F E000 100C 00000 0000C 55+ MVC 0(16,14),12(1) MOVE OUTPUT FROM PARM LIST 56+* TO CONVVAL AREA 0000BE 58D0 D004 00004 58 L 13,4(,13) LOAD CALLER GPR SAVEAREA 0000C2 58E0 D00C 0000C 59 L 14,12(,13) RESTORE GR14 0000C6 980C D014 00014 60 LM 0,12,20(13) RESTORE GR0 TO GR12 0000CA 47F0 E000 00000 61 B 0(,14) RETURN TO CALLER 62 *---------------------------------------------------------------------* 0000CE 0000 0000D0 0000000000000000 66 DOUBLE DC D'0' DOUBLE WORD WORKAREA 0000D8 0000000000000000 67 EDITAREA DC XL16'00' EDIT WORKAREA 0000E8 68 LTORG , USER LITERAL PLACE AT HERE
ダンプとアセンブル・リストからエラーの箇所を見つける
まずはダンプリストからABEND時のPSWとレジスターの内容を確認します。徴候ダンプを見るのが早くて簡単です。
IEA995I SYMPTOM DUMP OUTPUT 450 SYSTEM COMPLETION CODE=0C4 REASON CODE=00000004 TIME=10.53.05 SEQ=00032 CPU=0000 ASID=0020 PSW AT TIME OF ERROR 078D0000 80007FD6 ILC 6 INTC 04 ~~~~~~~~ ここがABENDした命令の次の命令のアドレス ACTIVE LOAD MODULE ADDRESS=00007F18 OFFSET=000000BE NAME=TEMPNAM0 DATA AT PSW 00007FD0 - D20FE000 100C58D0 D00458E0 000000 00000 000E8 4 MAINENTR CSECT , DEFINE CODE SECTION 5 MAINENTR AMODE 31 DEFINE DEFAULT AMODE 6 MAINENTR RMODE 24 DEFINE DEFAULT RMODE R:C 00000 7 USING *,12 DEFINE BASE REGISTER 000000 90EC D00C 0000C 8 STM 14,12,12(13) SAVE CALLER REGISTERS 000004 41C0 F000 00000 9 LA 12,0(,15) GR12 -> OUR 1ST BASE ADDRESS アセンブル・リストからベースレジスターは R12であることがわかる。 (自分で作ったプログラムなら見なくてもわかる) GR 0: 00000000 1: 00007F9C 2: 00000040 3: 009D29D4 4: 009D29B0 5: 009EC818 6: 00007FF0 7: FD000000 8: 009ECA10 9: 009ECAD8 A: 00000000 B: 009EC818 C: 00007F18 D: 80007F28 R12の内容はx7F18、ここがプログラムの ~~~~~~~~~~~ ペースアドレスとなる E: 00000006 F: 00000000 END OF SYMPTOM DUMP 00007FC0 58EE0304 58EE0130 B218E000 51E00006 *..........\..\.. 00007FD0 D20FE000 100C58D0 D00458E0 D00C980C K.\....}}..\}.q.* ~~~~~~~~~~~~~ 00007FE0 D01447F0 E0000000 CB1EE954 98DD0000 *}..0\.....Z.q... ABEND箇所はPSWが示す1つ前の命令なので、徴候ダンプなどに示された 命令長(ILC 6)分前に戻すと、xD20FE000100Cがその命令となる。 この場所は、x7FD6-x7F18=xBEなのでプログラムの範囲内であることがわかる。 実際にアセンブル・リストと照らし合わせると、 0000B8 D20F E000 100C 00000 0000C 55+ MVC 0(16,14),12(1) MOVE OUTPUT FROM PARM LIST 56+* TO CONVVAL AREA 0000BE 58D0 D004 00004 58 L 13,4(,13) LOAD CALLER GPR SAVEAREA で、MVC命令であることがわかる。
PSWが示すABENDアドレスはx7FD6、プログラムのペースアドレスはX7F18であることがわかります。x7FD6はプログラムの先頭からのオフセットxBEの位置です。PSWは次の命令を指すので、実際にABENDしたのは1つ前の命令です。ILC(命令長)が示す値を引くとxB8がABENDした命令の位置です。アセンブル・リストからこれがMVC命令であることがわかります。
この命令はGR1が示すアドレスのオフセット12の位置のメモリーの内容をGR14が示すアドレスにコピーするものです。
GPR VALUES 0-3 00000000 00007F9C 00000040 009D29D4 : ~~~~~~~~ 12-15 00007F18 80007F28 00000006 00000000 ~~~~~~~~
GR1とGR14の内容を確認すると、GR1はプログラム内で問題なさそうですが、GR14には6が入っています。つまりアドレス6番地に書き込もうとしています。そのため記憶保護例外S0C4 ABENDとなったようです。
では何故コピー先のアドレスを示すGR14に6などという誤った値が入ったのかを引き続き追求します。そのためにはアセンブル・リストでこの命令よりさらに前の命令列を確認します。
000064 4160 C0D8 000D8 31 LA R6,EDITAREA 32 STCKCONV STCKVAL=DOUBLE, CONVERT TO YYYYMMDD/HHMMSS... + CONVVAL=R6, + DATETYPE=YYYYMMDD,TIMETYPE=DEC 33+* MACDATE 05/30/98 @L1C 000068 34+ DS 0H 000068 5110 0000 00000 35+ LAE 1,0(0,0) ZERO ACCESS REGISTER 1 00006C 4110 C084 00084 36+ LA 1,IHB0001K POINT TO PARAMETER LIST 000070 9203 1002 00002 37+ MVI 2(1),3 SET DATETYPE FLAGS IN PARM LIST 000074 51E0 C0D0 000D0 38+ LAE 14,DOUBLE ADDRESS OF STCKVAL 000078 D207 1004 E000 00004 00000 39+ MVC 4(8,1),0(14) MOVE STCKVAL INTO PARM LIST 00007E 47F0 C0A0 000A0 40+ B IHB0001A BRANCH AROUND LIST 000084 41+IHB0001K DS 0F 000084 0000 42+ DC FL2'0' 000086 00 43+ DC FL1'0' 000087 00 44+ DC FL1'0' 000088 0000000000000000 45+ DC 2F'0' 000090 0000000000000000 46+ DC 2F'0' 000098 0000000000000000 47+ DC 2F'0' 0000A0 48+IHB0001A DS 0H 0000A0 9222 1003 00003 49+ MVI 3(1),34 SET TIMETYPE FLAGS IN PLIST @L1M 0000A4 58E0 0010 00010 50+ L 14,16(0,0) CVT ADDRESS 0000A8 58EE 0304 00304 51+ L 14,772(14,0) SFT ADDRESS 0000AC 58EE 0130 00130 52+ L 14,304(14,0) LX/EX FOR SERVICE ROUTINE 0000B0 B218 E000 00000 53+ PC 0(14) 0000B4 51E0 0006 00006 54+ LAE 14,R6 ADDRESS OF CONVVAL ~~~~~~~~~~~ ここでGR14にロードしている 0000B8 D20F E000 100C 00000 0000C 55+ MVC 0(16,14),12(1) MOVE OUTPUT FROM PARM LIST 56+* TO CONVVAL AREA 0000BE 58D0 D004 00004 58 L 13,4(,13) LOAD CALLER GPR SAVEAREA
アセンブル・リストを見ると、オフセットxB4のLAE命令でR6というラベルのアドレスがGR14にセットされています。ラベル名R6?って何でしょうか。実はここはマクロ命令による展開命令列です。実際に自分でソース・プログラム上に書いた命令ではありません。マクロ命令による展開命令列かどうかは命令の左側の通し番号の直後に+マークの有無でわかります。このABENDで問題となっているLAE命令にもMVC命令にも+マークが付いているのでマクロ命令による展開命令列であることがわかります。命令列をリスト上で上方向にさかのぼれば展開したマクロ命令がわかります。これはプログラマーがソース・プログラム上に書いたものです。
LA R6,EDITAREA STCKCONV STCKVAL=DOUBLE, CONVERT TO YYYYMMDD/HHMMSS... + CONVVAL=R6, + DATETYPE=YYYYMMDD,TIMETYPE=DEC
問題となっている命令列を展開したのはSTCKCONVマクロであることがわかります。一見すると問題なさそうですが、パラメーターをよく見てみると、CONVVALパラメーターに値として「R6」が指定されています。これがLAE命令でのラベル名R6に関係があるようです。
STCKCONVマクロの直前でGR6にEDITAREAのアドレスをロードしていますから、CONVVALパラメーターではGR6に格納されたアドレスの領域を指定したものですが、値の表記が誤っているため、マクロ内でR6をレジスター番号ではなくラベル名として処理されてしまったものです。正しくは次のようにマクロ命令を書かなければなりません。
LA R6,EDITAREA STCKCONV STCKVAL=DOUBLE, CONVERT TO YYYYMMDD/HHMMSS... + CONVVAL=(6), + DATETYPE=YYYYMMDD,TIMETYPE=DEC もしくは STCKCONV STCKVAL=DOUBLE, CONVERT TO YYYYMMDD/HHMMSS... + CONVVAL=(R6), + DATETYPE=YYYYMMDD,TIMETYPE=DEC
マクロ命令ではパラメーターの値にレジスターの内容を指定する場合は、レジスター番号を()でくくって記述するのが一般的です。この事は各マクロのマニュアルでも明記されています。ソース・プログラムだけを追っているとわかりにくいバグの例でもあります。
正しく記述されたSTCKCONVマクロの展開は次のようになります。
32 STCKCONV STCKVAL=DOUBLE, CONVERT TO YYYYMMDD/HHMMSS... + CONVVAL=(R6), + DATETYPE=YYYYMMDD,TIMETYPE=DEC 33+* MACDATE 05/30/98 @L1C 000068 34+ DS 0H 000068 5110 0000 00000 35+ LAE 1,0(0,0) ZERO ACCESS REGISTER 1 00006C 4110 C084 00084 36+ LA 1,IHB0001K POINT TO PARAMETER LIST 000070 9203 1002 00002 37+ MVI 2(1),3 SET DATETYPE FLAGS IN PARM LIST 000074 51E0 C0D0 000D0 38+ LAE 14,DOUBLE ADDRESS OF STCKVAL 000078 D207 1004 E000 00004 00000 39+ MVC 4(8,1),0(14) MOVE STCKVAL INTO PARM LIST 00007E 47F0 C0A0 000A0 40+ B IHB0001A BRANCH AROUND LIST 000084 41+IHB0001K DS 0F 000084 0000 42+ DC FL2'0' 000086 00 43+ DC FL1'0' 000087 00 44+ DC FL1'0' 000088 0000000000000000 45+ DC 2F'0' 000090 0000000000000000 46+ DC 2F'0' 000098 0000000000000000 47+ DC 2F'0' 0000A0 48+IHB0001A DS 0H 0000A0 9222 1003 00003 49+ MVI 3(1),34 SET TIMETYPE FLAGS IN PLIST @L1M 0000A4 58E0 0010 00010 50+ L 14,16(0,0) CVT ADDRESS 0000A8 58EE 0304 00304 51+ L 14,772(14,0) SFT ADDRESS 0000AC 58EE 0130 00130 52+ L 14,304(14,0) LX/EX FOR SERVICE ROUTINE 0000B0 B218 E000 00000 53+ PC 0(14) 0000B4 51E0 6000 00000 54+ LAE 14,0(0,R6) ADDRESS OF CONVVAL 0000B8 D20F E000 100C 00000 0000C 55+ MVC 0(16,14),12(1) MOVE OUTPUT FROM PARM LIST 56+* TO CONVVAL AREA
エラーの原因となったLAE命令では、R6ではなく0(0,R6)の表記に変わり、6番地ではなくレジスター6番の内容をベースにしたアドレスがGR14にロードされることになり、プログラムは意図した通りに正しく実行されます。
サンプル・プログラムのソースコード
MAINENTR CSECT , DEFINE CODE SECTION MAINENTR AMODE 31 DEFINE DEFAULT AMODE MAINENTR RMODE 24 DEFINE DEFAULT RMODE USING *,12 DEFINE BASE REGISTER STM 14,12,12(13) SAVE CALLER REGISTERS LA 12,0(,15) GR12 -> OUR 1ST BASE ADDRESS LR 15,13 SAVE CALLER SAVEAREA CNOP 0,4 INSURE FULL WORD BOUNDARY BAS 13,*+4+72 AROUND OUR SAVEAREA DC 18F'-1' OUR GPR SAVEAREA ST 15,4(,13) SAVE CALLER SAVEAREA POINTER ST 13,8(,15) SET BACK CHAIN FOR LINK TRACE SPACE , STCK DOUBLE GET CURRENT CLOCK LA R6,EDITAREA STCKCONV STCKVAL=DOUBLE, CONVERT TO YYYYMMDD/HHMMSS... + CONVVAL=R6, + DATETYPE=YYYYMMDD,TIMETYPE=DEC *---------------------------------------------------------------------* L 13,4(,13) LOAD CALLER GPR SAVEAREA L 14,12(,13) RESTORE GR14 LM 0,12,20(13) RESTORE GR0 TO GR12 B 0(,14) RETURN TO CALLER *---------------------------------------------------------------------* DOUBLE DC D'0' DOUBLE WORD WORKAREA EDITAREA DC XL16'00' EDIT WORKAREA LTORG , USER LITERAL PLACE AT HERE YREGS , OS: REGISTER EQUATES END