ダンプリスト解析入門②

By 神居 - Posted: 2012/08/23 Last updated: 2012/08/23 - Leave a Comment

ダンプリスト解析入門②:ABEND箇所を特定する

プログラムの誤りを正すための一般的な手順は概ね以下の通りとなります。

まずは、モジュール内のどこでプログラムがABENDしたのかを特定します。それから、エラーの原因を究明していきます。S0C4やU4039といったABENDコードは、ABENDさせられた直接の理由を示しますが、それ自体がABENDした原因にはなりません。例えば、S0C4は誤ったアドレスのメモリー領域にアクセスしたことを示しますが、そのような理由がわかっても問題は解決しません。プログラムのどこで不正なアドレスにアクセスしたのか?どうして誤ったアドレスを指し示してしまったのか?をダンプリストを解析することで明らかにしていきます。


PSW

PSWには最後に割り込みを起こした命令の次の命令のアドレスが格納されています。S0C1やS0C4といったプログラムチェックはプログラムチェック割り込み、ABENDマクロによるUnnnnといったユーザーABENDはSVC割り込み、どちらも割り込みですからPSWの命令アドレス部を見ることで、プログラムのどこでABENDしたかを特定することができます。多くの場合、PSWはABENDコードに続いて最初に確認される項目です。
※PSWの命令アドレスは多くの場合、次の命令アドレスを指すが、S0CxABENDの場合はプログラム割込みコードによってはABENDした命令そのものを指す場合がある。例えばS0C4ABENDの場合、仮想アドレスは正しいが記憶キーが異なるために書き込みできない場合(記憶保護例外)は命令は抑止されPSWは次の命令アドレスを指すが、仮想アドレスそのものが誤りの場合(セグメント変換例外)は命令は取消(無効化)されPSWはABENDした命令そのもののアドレスを指す。

PSWが示す命令アドレスから、プログラム・モジュールのベースアドレスを引けば、モジュール内オフセットがわかります。オフセットはプログラム内のどこでABENDしたかを示します。オフセットはアセンブル・リストではロケーション・カウンターとして表示されています。
ベースアドレスは汎用レジスターの内容から求めます。自分で作ったプログラムであれば、ABENDしたモジュールがどのレジスターをベースレジスターにしているかはすぐわかるでしょう。例えばGR12をベースレジスターにしているなら、ABEND時のGR12の内容がベースアドレスとなります。
MVSであれば、PSWと汎用レジスターの内容はJOBログ上の徴候(SYMPTOM)ダンプに表示されます。MSPやVOS3で徴候ダンプがない場合は、ダンプリスト上で確認します。PSWは、ダンプリストの冒頭に表示されます。レジスター内容は、「REGS AT ENTRY TO ABEND」の文字列をスキャンすれば簡単に見つかります。(MVSのダンプでは、「REGS AT ENTRY TO ABEND」または「GPR VALUES」の文字列をスキャンする)
一般的なプログラムでは、モジュールの先頭=オフセット=0がベースアドレスとなるようにUSINGを指定していますから、PSWの命令アドレスからGRnnが示すベースアドレスを差し引けばいいのですが、例外もあります。例えば一部のOSモジュールなど、MVSの標準リンケージ規約が使われず、GR15が入口点アドレスを指さないようなモジュールでは、モジュールの先頭でBALR命令を使用し自分自身ベースアドレスを求めるようなものがあります。このようなモジュールではUSINGはBALR命令の後で定義するため、ベースアドレスはモジュールの先頭にはなりません。



ABEND時のPSWと最終割込み時のPSW

ABENDしたアドレスが自分のプログラムではない場合があります。この例では、S0C4でABENDしたアドレスは00EA0C76ですが、このプログラムではベースレジスターにGR12を使用しており、GR12が示すベースアドレスは07500F20です。ぱっと見ても自分のプログラムとはかけ離れた場所でABENDしています。また、徴候ダンプでもモジュール名はUNKNOWN、NO ACTIVE MODULE FOUNDとなっておりJCLのEXEC文で指定したプログラム・モジュールや、このプログラムからLINKやLOADマクロによってローディングされたモジュールでもなさそうです。
このような場合は、ダンプリストから文字列「PRB:」を探します。PRBは、タスクで実行されるプログラムを管理するOSの制御表で、ジョブ・ステップで最初に実行されるプログラムもPRBによって管理されます。PRBにはこのプログラムが最後に起こした割込み時のPSWが格納されており、ダンプ上ではOPSWの見出しで表示されます。このPSWと徴候ダンプやダンプリストの冒頭部に表示されたPSWが違っていれば、ABENDは直接プログラム内で起きたのではなく、プログラム内で起こした割込みの延長で起きたものとなります。そこで、PRBで示されるOPSWを基に最後に起こした割込み箇所を調べます。
(プログラム内でS0C1やS0C4などのプログラムチェックが起きれば、それ自体がプログラムチェック割込みになり、その割込み発生アドレスがABENDアドレスとなるため、PRB内の最終割込みPSWとABEND時のPSWは一致する。)

自分のプログラムの外でABENDしたことがはっきりしたからといって、自分のプログラムの問題ではないと決めつけてはいけません。この例では、SVC19つまりOSのOPEN SVCルーチンの中でABENDしていますが、OPEN SVCルーチンの問題やバグである可能性は0ではないものの、限りなく0に近いです。マクロ命令などでOSのサービス(API)を要求して、その処理の中でABENDするのは、マクロに指定したパラメーターの設定ミスなど、99.99%はマクロの書き方やパラメーターの誤りによるものです。まずは素直に、私がOPENマクロを間違えて書いたからOSの中でABENDしてしまった、と自分のプログラムを疑います。この例では、ABENDの原因はDCBを16MB境界の上に置いていたから(RMODE=ANYのプログラム内にDCBを定義してしまった)でした。
マクロ命令のパラメーター・ミスだけでなく、パラメーターで指定した領域の初期設定ミスなど、とにかく関連するものについて調べます。うろ覚えで使ったマクロなら改めてマニュアルで確認するなども必要です。マクロ命令のパラメーターとしてレジスター番号を指定するような場合、()で括ることを忘れたためにまったく意図しない命令展開になることがあります。


プログラム内でのABENDなのに場所がわかりにくい例

Posted in ダンプ解析入門 • • Top Of Page