- 「メインフレーム・コンピューター」で遊ぼう - http://www.arteceed.net -

ダンプリスト解析入門(番外編①)

ダンプリスト解析入門(番外編①):正しいアドレスなのにS0C4でABENDする??

MVCL命令でデータの移動先アドレスや移動するデータの長さなどを間違えた場合に、データの移動中にプログラムチェック割り込みを起こし、S0C4でABENDすることがあります。命令で指定したレジスターはABENDした時点の移動元や移動先のアドレス、残りの領域長やデータ長を示します。

    ----+----1----+----2----+----3----+----4----+----5----+----6----+----7--
             :
             GETMAIN RU,LV=4000,LOC=BELOW
             LR    R2,R1
             LR    R0,R1
             L     R1,=F'4096'
             LA    R14,DATA
             LR    R15,R1
             MVCL  R0,R14                   MOVE DATA TO OBTAINED STORAGE
             :
    DATA     DC    120CL36'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
             :
    

この命令は、GR14が示すアドレスの領域内データを、GR0が示すアドレスの領域にコピーするものです。領域の長さは対となっているGR1およびGR15に入っています。この命令実行中に次に示すようなPSWとレジスターでABENDしました。

    DATA AT PSW  00007F08 - 41E0C03C  18F10E0E  00000ACA
    GR 0: 0000A000   1: 00000060                        
       2: 00009060   3: 009D29D4                        
       4: 009D29B0   5: 009EC818                        
       6: 009C1FE0   7: FD000000                        
       8: 009EC9E0   9: 009ECAD8                        
       A: 00000000   B: 009EC818                        
       C: 80007EE0   D: 00006F40                        
       E: 00008EBC   F: 00000060                        
    

ABENDした時点のGR0はx0000A000、GR14はx00008EBCで、残りデータ長はx60バイトを示しています。SYSUDUMPに出力された移動元と移動先の領域内容は次の通りでした。

    GR14=x00008EBC(移動元)
    =======================
    00008E00 F6F7F8F9C1C2C3C4C5C6C7C8C9D1D2D3 D4D5D6D7D8D9E2E3E4E5E6E7E8E9F0F1
    00008E20 F2F3F4F5F6F7F8F9C1C2C3C4C5C6C7C8 C9D1D2D3D4D5D6D7D8D9E2E3E4E5E6E7
    00008E40 E8E9F0F1F2F3F4F5F6F7F8F9C1C2C3C4 C5C6C7C8C9D1D2D3D4D5D6D7D8D9E2E3
    00008E60 E4E5E6E7E8E9F0F1F2F3F4F5F6F7F8F9 C1C2C3C4C5C6C7C8C9D1D2D3D4D5D6D7
    00008E80 D8D9E2E3E4E5E6E7E8E9F0F1F2F3F4F5 F6F7F8F9C1C2C3C4C5C6C7C8C9D1D2D3
    00008EA0 D4D5D6D7D8D9E2E3E4E5E6E7E8E9F0F1 F2F3F4F5F6F7F8F9C1C2C3C4C5C6C7C8
    00008EC0 C9D1D2D3D4D5D6D7D8D9E2E3E4E5E6E7 E8E9F0F1F2F3F4F5F6F7F8F9C1C2C3C4
    00008EE0 C5C6C7C8C9D1D2D3D4D5D6D7D8D9E2E3 E4E5E6E7E8E9F0F1F2F3F4F5F6F7F8F9
    00008F00 C1C2C3C4C5C6C7C8C9D1D2D3D4D5D6D7 D8D9E2E3E4E5E6E7E8E9F0F1F2F3F4F5
    00008F20 F6F7F8F9C1C2C3C4C5C6C7C8C9D1D2D3 D4D5D6D7D8D9E2E3E4E5E6E7E8E9F0F1
    00008F40 F2F3F4F5F6F7F8F9C1C2C3C4C5C6C7C8 C9D1D2D3D4D5D6D7D8D9E2E3E4E5E6E7
    00008F60 E8E9F0F1F2F3F4F5F6F7F8F9C1C2C3C4 C5C6C7C8C9D1D2D3D4D5D6D7D8D9E2E3
    00008F80 E4E5E6E7E8E9F0F1F2F3F4F5F6F7F8F9 C1C2C3C4C5C6C7C8C9D1D2D3D4D5D6D7
    00008FA0 D8D9E2E3E4E5E6E7E8E9F0F1F2F3F4F5 F6F7F8F9C1C2C3C4C5C6C7C8C9D1D2D3
    00008FC0 D4D5D6D7D8D9E2E3E4E5E6E7E8E9F0F1 F2F3F4F5F6F7F8F9C1C2C3C4C5C6C7C8
    00008FE0 C9D1D2D3D4D5D6D7D8D9E2E3E4E5E6E7 E8E9F0F1F2F3F4F5F6F7F8F900000000
    
    GR0=x0000A000(移動先)
    ======================
    00009F00 C1C2C3C4C5C6C7C8C9D1D2D3D4D5D6D7 D8D9E2E3E4E5E6E7E8E9F0F1F2F3F4F5
    00009F20 F6F7F8F9C1C2C3C4C5C6C7C8C9D1D2D3 D4D5D6D7D8D9E2E3E4E5E6E7E8E9F0F1
    00009F40 F2F3F4F5F6F7F8F9C1C2C3C4C5C6C7C8 C9D1D2D3D4D5D6D7D8D9E2E3E4E5E6E7
    00009F60 E8E9F0F1F2F3F4F5F6F7F8F9C1C2C3C4 C5C6C7C8C9D1D2D3D4D5D6D7D8D9E2E3
    00009F80 E4E5E6E7E8E9F0F1F2F3F4F5F6F7F8F9 C1C2C3C4C5C6C7C8C9D1D2D3D4D5D6D7
    00009FA0 D8D9E2E3E4E5E6E7E8E9F0F1F2F3F4F5 F6F7F8F9C1C2C3C4C5C6C7C8C9D1D2D3
    00009FC0 D4D5D6D7D8D9E2E3E4E5E6E7E8E9F0F1 F2F3F4F5F6F7F8F9C1C2C3C4C5C6C7C8
    00009FE0 C9D1D2D3D4D5D6D7D8D9E2E3E4E5E6E7 E8E9F0F1F2F3F4F5F6F7F8F9C1C2C3C4
    0000A000 00000000000000000000000000000000 00000000000000000000000000000000 <==
    

プログラムではGR14が示す移動元は、自プログラム領域内でアドレスと長さの指定には問題がありません。となれば移動先のアドレスxA000が問題となったものと考えられます。しかしダンプには問題であろうアドレスxA000は有効なストレージ領域として出力されています。仮想アドレスとして存在しているのにどうして不正アドレスでS0C4してしまうのか?という疑問も生じます。

結論から言うと、この場合確かにxA000は誤ったアドレスなのです。プログラム・コードを見るとGETMAINで長さを4000バイトとして移動先の領域を割り振っているのに、MVCL命令は4096バイトの長さで実行しています。そのため4000バイト移動し終わった時点でABENDしたものです。
アドレスA000の領域は存在しないのですからダンプには出てこないはずですが、出てきているために、ならば有効な仮想記憶域ではないか?と思ってしまうわけです。
手元にプログラムコードがあって、単純なミスのようなバグであればダンプがどうであれ、簡単に原因はわかりますが、複雑なプログラムであったり、過去に作られたもので内容もよくわからない、といったような場合では、ダンプされた領域の内容から問題を起こしたモジュールや箇所を特定したい場合もあります。プログラムの規模が大きくなると原因を作った箇所と実際にABENDしたモジュールが違う、などということはよくあることです。ダンプ上でxA000は、Storage not available であるとはっきり出ていればいいのですが、上記のようにダンプにも領域として出てきてしまうと、どうしてこのアドレスでS0C4になるのか?と考えてしまうかも知れません。

実はダンプに出ているxA000からの領域は、このプログラムがABENDした後に、MVSのABEND処理によって割り振られた領域です。このケースではSYSUDUMP(SYSABEND)を出力するための作業域、関連するモジュールのローディングなどに使われていました。ダンプリストはABENDした時点の空間内の記憶域を編集して出力しますが、ABENDそのものを処理したりダンプを出力するためにMVSのRTMなど関連するコンポーネントのモジュールが実行されます。そのためABEND発生からダンプのためにメモリー内容が読み取られるまでの間にOSの作業域として空間内の領域が使用され、そこがたまたまアプリケーション・プログラムが割り振った領域の直後に続いて割り振られると、ダンプ上は有効な仮想記憶域が続いているように見えるのです。
落ち着いて見ればその後に、OSのモジュール名らしきものやABEND処理に使われそうな内容の文字列などが入っていれば当たりもつきますが、ヌルなどがある程度続いていたりすると元々GETMAINしていたアプリケーションの領域ではないのか?とも思えてしまうのです。このケースではSYSUDUMPではなくSYSMDUMPでバイナリーダンプの出力に変えたところ、xA000の領域はダンプ上存在せず Storage not available となっていました。SYSMDUMPはフォーマットしないのでより少ない作業域で処理されたものと考えられます。

もしMVCL命令実行中にABENDしたので関連するレジスターからダンプでストレージ内容を確認したら、仮想記憶域として出力されているからS0C4するようには見えないが?と思ったら、データの移動元や移動先アドレスが、ちょうどページの始まりを示すきりのいいアドレス値になっていないかを確認してみて下さい。もしこのケースのようにxA000など仮想ページの開始アドレスつまりページバウンダリーになったアドレスであれば、間違いなくデータ移動中に有効なページを超えてデータを処理しようとしたものです。GETMAINしていない領域でもまたFREEMAINしてしまった領域でも、ページの1部でも有効に残っていればそのページの4KBの中であればS0C4にはなりません。そのページを超えて次のページが割り振られていないとそこでS0C4となります。

いずれにしてもダンプリスト(特にSYSUDUMPやSYSABEND)で出てくるメモリー内容は、純粋にアプリケーション・プログラムでだけ使われている領域だけではない、ABENDした時にはなかったけどABEND処理の過程でリージョン内の領域が割り振られて使われた結果ダンプにでてくる領域もあるのだ、ということを知った上でダンプを調べると余計な疑問を持たずに済みます。原因がなかなか掴めないとどうしても他の誰かが悪いのでは?と考えたくなりますが、ABENDの原因は99.999%自分の作ったプログラムにあるのだと考える方が無難です。