モジュール内のどこでプログラムがABENDしたのかが特定できたら、エラーの原因を究明していきます。まずは、ABENDコードによってABENDさせられた直接の理由を確認します。その後、どうしてそのようなエラーを引き起こしたのかという原因を調べていきます。
ABENDコード
ABENDコードはプログラムの異常終了の理由を示すもので、大きくシステムABENDコードとユーザーABENDコードに大別されます。ユーザーABENDコードは「Unnnn(nnnnは0から4095の10進数)」の形式で、ABENDマクロを発行したユーザー・プログラムで指定した値です。ユーザーABENDは、入力データなどに誤りがあった場合や想定していないデータが渡されたような場合に、そのまま処理しては正しい結果を出すことができないことをユーザー・プログラム自らが検知してプログラムの処理をキャンセルするような場合に使用されます。
ユーザーABENDの場合のABENDコードはユーザー・プログラムの仕様によって決まるので、エラーの原因や対処方法などはユーザー・プログラムのマニュアルなどで明記されます。ユーザー自らが作ったアプリケーション・プログラムではなく、メーカーやベンダーのソフトウェア製品などでは、それらの製品のマニュアルにABENDコードの意味や対処方法が記載されています。
システムABENDコードは「Sxxx(xxxは001からFFFの16進数)」の形式で、OSが割り当てたコードです。システムABENDは、プログラムのエラーを検知したOSによって強制的にABENDさせられるものです。その原因にはプログラムのバグもありますが、入出力エラーやハードウェア・エラーなどアプリケーション・プログラムのせいではないものもあります。
システムABENDの場合のABENDコードは、システム・コードあるいはメッセージのマニュアルなどにコードの意味や対処方法が解説されています。
S0Cx
S0Cxはプログラム割込みによるABENDです。プログラム割込みはCPUの割込みの1つで、存在しない命令を実行しようとしたり、数値を0で割ろうとする(0除算)など演算不可能な計算をしようとした場合などに、CPUが命令の実行を抑止したことを通知するものです。この割込みが発生すると、MVSはプログラム割込みルーチンによってエラー処理を行います。プログラム・エラーの原因は割込みコードによって通知されますが、これはS0CxABENDの理由を示します。0Cxのxと理由コード(プログラム割込みコード)は、ほとんどの場合同じですがS0C4ABENDのように複数の理由で構成されるものもあります。例えば、同じS0C4ABENDでもPSWキーと異なる領域にアクセスした記憶保護例外(理由コード4)と存在しないアドレスにアクセスした(理由コード10や11)では原因が異なります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
同じS0C4ABENDでも... PSW AT TIME OF ERROR 078D0000 80007F20 ILC 4 INTC 04 ~~~~ 割込みコードは4で記憶保護例外 ACTIVE LOAD MODULE ADDRESS=00007EB8 OFFSET=00000068 NAME=TEMPNAM0 DATA AT PSW 00007F1A - 00645010 20004130 00C84110 : PSW AT TIME OF ERROR 078D0000 80007F1C ILC 4 INTC 11 ~~~~ 割込みコードは11でページ変換例外 ACTIVE LOAD MODULE ADDRESS=00007EB8 OFFSET=00000064 DATA AT PSW 00007F16 - F0085820 C1405010 20004130 : |
S0CxABENDは、ほとんどの場合プログラムのバグです。中には入力データが誤っていたため(例えば、数値なのに文字列が入っていた)に、そのデータで演算命令を実行した結果S0C7などを引き起こすこともあります。コーディング・ミスではありませんが、データの正当性をチェックしていれば防げる類のものでプログラム・デザインの甘さに起因するものです。これらも広義のバグと言えるでしょう。
S1xx、S2xx、S3xx、S4xx、S5xx、S6xx、S7xx、S8xx、S9xx、SAxx、SBxx…
S100以上のコードの場合、システムABENDコードの下2桁はエラーを検知したSVC処理のSVC番号を示します。例えば、S80AはSVC10でGETMAIN、S213はSVC19でOPENの各サービスでのエラーです。
コードの下2桁がSVC番号ということは覚えておくと便利です。ABENDコードを見ればどのSVCがエラーになったかがわかるため、エラーの箇所や原因を特定しやすくなるからです。
GETMAINやOPENなど様々なマクロ命令がありますが、どのマクロが何番のSVCを出すかはアセンブリー・リストを見ればわかります。1つのプログラム・モジュール内で何十ものマクロ命令を使うことなどほとんどありません。せいぜい数種類でしょう。最初のうちはアセンブルした後にリストを見て展開された命令列を確認したり、翻訳された命令コードを見ることで自分がプログラムで書いたマクロがどのSVCを出すかなどはすぐに覚えるものです。発行したマクロの処理を行うSVC内でABENDするのは、ほとんどのケースが誤ったパラメーターでマクロを発行したことによります。そういう意味でも多くはプログラムのバグ、ということになります。
レジスター
レジスター(ここでは汎用レジスターを指す)の内容は、ABEND原因を調べる上でとても重要です。特に、S0C4やS0C7といったアドレスを指定してメモリーにアクセスしたり演算を行ったりする命令でABENDした場合は、命令が指しているレジスターの内容は重要です。また、誤ったアドレスに分岐してしまったような場合も、レジスターの内容はプログラムがABENDに至るまで処理がどこまで行われていたのかをトレースする重要な手がかりにもなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
SYSTEM COMPLETION CODE=0C4 REASON CODE=00000010 TIME=14.14.54 SEQ=00011 CPU=0000 ASID=0020 PSW AT TIME OF ERROR 078C0000 00EA0C76 ILC 4 INTC 10 NO ACTIVE MODULE FOUND NAME=UNKNOWN DATA AT PSW 00EA0C70 - 1B224111 0000BF27 10014770 GR 0: FD000008 1: 00500F78 2: 00000000 3: 00EA030A 4: 009D0E88 5: 009FDB90 6: 87500F78 7: 00F98B80 8: 00000000 9: 80FFF01C A: 009FDC50 B: 009D0E88 C: 07500F10 D: 87500F20 E: 90EA0350 F: 009D0E88 END OF SYMPTOM DUMP |
ABEND時のレジスター内容は、徴候(SYMPTOM)ダンプに表示されます。あるいはダンプ・リストのレジスター表示部「GPR VALUES」に出力されています。しかし、SVCルーチンの中でABENDしたような場合、徴候ダンプやダンプ・リストのレジスター表示部は実際にABENDを起こした時点のレジスター内容なので、アプリケーション・プログラムがマクロ命令などを発行した後のOS側の処理で内容が変わってしまっています。PSWでABEND箇所を特定した時と同様に、ABEND時点ではなく最後に割込みを起こした時点のレジスター内容を求める必要が出てくることがあります。
マクロ命令発行によるSVC呼び出しの場合、アプリケーション・プログラムが最後に起こした割込みはSVC割込みとなり、SVC命令を実行した時点(最後に割込みを起こした時点)のレジスター内容はPSWが保管されているPRBの次に表示されているSVRB内に退避されています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
PRB: 009EC9B8 -0020 XSB...... 7FFFEF08 FLAGS2... 00 RTPSW1... 00000000 …;…; -000C 00000000 FLAGS1... 00000000 WLIC..... 00020013 ~~~~~~~~ +0000 RSV...... 00000000 00000000 SZSTAB... 00110082 …;…; +0010 OPSW..... 078D0000 87500F86 SQE...... 00000000 …;…; ~~~~~~~~~~~~~~~~~~ SVRB: 009FDB90 -0020 XSB...... 7FFFC638 FLAGS2... 00 RTPSW1... 078C0000 …;…; -000C 00500000 FLAGS1... 00000000 WLIC..... 00040010 …;…; +0000 RSV...... 00000000 00000000 SZSTAB... 001ED022 …;…; +0010 OPSW..... 078C0000 00EA0C76 Q........ 00000000 …;…; +0020 GPR0-3... FD000008 87500F78 07500F9C 009D29D4 ~~~~~~~~ +0030 GPR4-7... 009D29B0 009EC818 009C1FE0 FD000000 +0040 GPR8-11.. 009EC600 009ECAD8 00000000 009EC818 +0050 GPR12-15. 07500F10 87500F20 80FC8308 00006F60 |
自分のプログラム内でABENDしたのであれば、徴候ダンプに表示されているPSWとレジスター内容でアセンブリー・リストとダンプ・リストのメモリー内容を照らし合わせればいいのですが、自分のプログラム外で(例えば、発行したマクロの延長で呼ばれるSVCルーチン等)のABENDであれば、単に徴候ダンプの内容だけではなく、ダンプ・リストのPRBとSVRBから自分のプログラムが最後に起こした割込み(SVCの発行)時点のPSWとレジスターを求めて、アセンブリー・リストとダンプ・リストのメモリー内容を照らし合わせます。もちろん、SVCルーチンの処理エラーなどABENDコードのマニュアルで原因が判明できるのであれば、対応するプログラム・コードを見直して正しく修正すればいいのです。