メインフレームプログラムがCEEダンプによってクラッシュする行を見つける方法

メインフレームを使用してC ++で作業を習得する必要があり、プログラムがクラッシュした場所とその原因を特定する方法に問題がありました。 USSのz / OSオペレーティングシステム下のメインフレームでのプログラミングに関連するすべてのものを直ちに予約してください。 一方で、それは初歩的ですが、IBMのドキュメントでこれをすべて見つけることはそれほど簡単ではありません。 さらに、少なくともHLASMを読み取れる必要があります。



以下のドキュメントでは、CEEダンプによってプログラムがクラッシュする行を見つける方法を説明します。



以下は、起動すると確実に落ちるように書かれた短いプログラムです。 私はプログラムを複雑にしませんでした。C++プログラマーにとっては簡単すぎるように見えますが、タスクはコード内ですぐにエラーを見つけるのではなく、リストからそれを見つけることです。 実際には、プログラムははるかに大きく、長くなります。



int f1(int a, char *b) { char *value = 0L; value[0] = '\0'; return(0); } int main() { f1(1, ""); return(1); }
      
      







行を見つけるには、リストを使用してプログラムをコンパイルする必要があります。これは次のように行われます



1. XPLINKなし

 c++ -Wc,list'(t1.list)' -c t1.C c++ -o t1 t1.o
      
      







2.c XPLINK

 c++ -Wc,xplink -Wc,list'(t2.list)' -c t1.C c++ -Wl,xplink -o t2 t1.o
      
      







キーは-Wc、list '(t1.list)'で、このファイルのリストを強制的に生成します。

Makefileでは、これは次のように追加されます。

 # Here is where we get convlit(iso8859-1) and __LIBASCII # XCCFLAGS = $(CCFLAGS_ASCII) -Wc,list'($*.list)' XCPPFLAGS = $(CPPFLAGS_ASCII) -Wc,list'($*.list)'
      
      







Cプログラムの1行目、C ++の2行目。

プログラムを実行し、ダンプと以下のメッセージを受け取りました。



 /u/mddegt/sb/omni/cpp/test:>t1 CEE3204S The system detected a protection exception (System Completion Code=0C4). From entry point f1(int,char*) at compile unit offset +0000002A at entry offset +0000002A at address 1000A95A. Segmentation fault /u/mddegt/sb/omni/cpp/test:>t2 CEE3204S The system detected a protection exception (System Completion Code=0C4). From entry point f1(int,char*) at compile unit offset +00000016 at entry offset +00000016 at address 100063D6. Segmentation fault
      
      







詳細に触れない場合、必要な情報はすでにあります。 プログラムがf1関数に該当することがわかり、オフセットがあります。 ここで、ソースと同じディレクトリに生成されたリストが必要です(t1.list、t2.list。XPLINKのないプログラムの場合はT1、XPLINKのあるプログラムの場合はt2)。



リストでは、プログラムがクラッシュした関数の始まりを探します。



1. XPLINKなし



 15694A01 V1 R6 z/OS C++ t1.C: f1(int,char*) 02/14/06 15:42:32 3 OFFSET OBJECT CODE LINE# FILE# PSEUDOASSEMBLYLISTING 000001 | * void f1(); 000002 | * 000003 | * int f1(int a, char *b) f1(int,char*) 000018 000003 | DS 0D 000018 47F0 F001 000003 | B 1(,r15) 00001C 01C3C5C5 CEE eyecatcher 000020 000000C8 DSA size 000024 000000D8 =A(PPA1-f1(int,char*)) 000028 5050 D028 000003 | ST r5,40(,r13) 00002C 5850 D04C 000003 | L r5,76(,r13) 000030 End of Prolog
      
      







2. with XPLINK



 15694A01 V1 R6 z/OS C++ t1.C: f1(int,char*) 02/14/06 16:02:24 3 OFFSET OBJECT CODE LINE# FILE# PSEUDOASSEMBLYLISTING 000001 | * void f1(); 000002 | * 000003 | * int f1(int a, char *b) 000018 @1L0 DS 0D 000018 00C300C5 =F'12779717' XPLink entrypoint marker 00001C 00C500F1 =F'12910833' 000020 00000090 =F'144' 000024 00000088 =F'136' f1(int,char*) 000028 000003 | DS 0D 000028 9067 4788 000003 | STM r6,r7,1928(r4) 00002C End of Prolog
      
      







最初の列はオフセット、その前は生成されたコード、3番目はソースファイルの行番号です。

ご覧のとおり、XPLINKのない単純なプログラムがすぐに開始され、オフセット000018が取得され、XPLINKのある関数が最初にヘッダー(青)に移動し、次にプログラムが開始され、オフセット000028で開始されます。したがって、関数の初期シフトを計算しました 次に、初期オフセットに、プログラムがクラッシュしたオフセットを追加します。 すべての計算は16進形式です。



1.18 + 2A = 42

2.28 + 16 = 3E



リストには、すべてが落ちた行を見つけることが残っています。 これを行うには、結果のオフセットが表示されるまで関数を下げます。 この場合、関数自体の範囲を超えてはいけません。 超えた場合、いくつかの理由が考えられます。

1.ソースは、プログラムのビルド時のものとは異なります。

2.バイアスの計算のどこかで、ミスをして誤ってカウントしました。

3.一般的に何を検討しましたか。



1。

  000034 5020 50C0 000003 | ST r2,b(,r5,192) 000004 | * { 000005 | * .char *value = 0L; 000038 4110 0000 000005 | LA r1,0 00003C 1821 000005 | LR r2,r1 00003E 5020 50C4 000005 | ST r2,value(,r5,196) 000006 | * .value[0] = '\0'; 000042 9200 2000 000006 | MVI (char)(r2,0),0 000007 | * .return(0); 000008 | * } 000046 000008 | @1L6 DS 0H
      
      





2。

  000030 5020 4844 000003 | ST r2,b(,r4,2116) 000004 | * { 000005 | * .char *value = 0L; 000034 4130 0000 000005 | LA r3,0 000038 1813 000005 | LR r1,r3 00003A 5010 47E0 000005 | ST r1,value(,r4,2016) 000006 | * .value[0] = '\0'; 00003E 9200 1000 000006 | MVI (char)(r1,0),0 000007 | * .return(0); 000008 | * } 000042 000008 | @1L6 DS 0H
      
      





どちらの場合も、同じ行番号6を取得しました。アセンブラーに注意を払わずに、3列目の行番号000006を確認します。必要に応じて、このリストのエラーを引き続き検索できますが、ソースに移動します。



さらに、私はXPLINKなしで2つのバージョンを提供せず、XPLINKを使用して、最初のバージョンに限定します。



より高い情報を含むstderr出力がなかった場合(エラーメッセージが出力されることを意味します)、これはCEEダンプファイルでも見つけることができます。 これを行うには、CEEダンプを開き、最初のテーブルを探します。



  Traceback: DSA Addr Program Unit PU Addr PU Offset Entry E Addr E Offset Statement Load Mod Service Status 10020CF0 CEEHDSP 046C0B00 +000048DA CEEHDSP 046C0B00 +000048DA CEEPLPKA UK10749 Call 100202B0 1000A930 +0000002A f1(int,char*) 1000A930 +0000002A *PATHNAM Exception 10020210 1000A968 +0000006E main 1000A968 +0000006E *PATHNAM Call 100200F8 044EFCB6 +000000B4 EDCZMINV 044EFCB6 +000000B4 CEEEV003 Call 10020030 CEEBBEXT 046C69E8 +000001A6 CEEBBEXT 046C69E8 +000001A6 CEEPLPKA HLE7709 Call
      
      





この表では、最後の行で例外を探します。これは、プログラムがクラッシュした関数、Enrty列の関数名、E Offset列でプログラムがクラッシュしたオフセットです。



同じ表に、関数の完全なスタックがあります(エントリ列)。 同様に、呼び出された関数への呼び出しが、呼び出し元の関数のどの行にあったかを判断できます。



コードにエラーの場所が表示されない場合の対処方法。



これを行うには、CEEダンプ内のアセンブラーコードを調べます(z / OSのアセンブラー命令の説明は、操作のプリンシパル、第7章にあります)。



  000006 | * .value[0] = '\0'; 000042 9200 2000 000006 | MVI (char)(r2,0),0
      
      





ご覧のとおり、この命令はアドレス(r2 + 0)に0を書き込もうとします。 ゼロの代わりに、他のオフセットがありますが、この場合は0です。問題は、レジスタ内のr2についてです。



これを行うために、CEEダンプには、これらのレジスタが指すレジスタとメモリ領域の印刷があります。



  Condition Information for Active Routines Condition Information for (DSA address 100202B0) CIB Address: 10021630 Current Condition: CEE3204S The system detected a protection exception (System Completion Code=0C4). Location: Program Unit: Entry: f1(int,char*) Statement: Offset: +0000002A Machine State: ILC..... 0004 Interruption Code..... 0004 PSW..... 078D1400 9000A95E GPR0..... 100087E8 GPR1..... 00000000 GPR2..... 00000000 GPR3..... 00000001 GPR4..... 1000A9A8 GPR5..... 100202B0 GPR6..... 1000AAAC GPR7..... 1000A0F0 GPR8..... 00000030 GPR9..... 80000000 GPR10.... 844EFCAA GPR11.... 846C69E8 GPR12.... 1001A7D0 GPR13.... 100202B0 GPR14.... 9000A9D8 GPR15.... 1000A930 FPC...... 00000000 FPR0..... 4DBE5D7C A198209F FPR1..... 00000000 00000000 FPR2..... 00000000 00000000 FPR3..... 00000000 00000000 FPR4..... 00000000 00000000 FPR5..... 00000000 00000000 FPR6..... 00000000 00000000 FPR7..... 00000000 00000000 FPR8..... 00000000 00000000 FPR9..... 00000000 00000000 FPR10.... 00000000 00000000 FPR11.... 00000000 00000000 FPR12.... 00000000 00000000 FPR13.... 00000000 00000000 FPR14.... 00000000 00000000 FPR15.... 00000000 00000000 Storage dump near condition, beginning at location: 1000A94A +000000 1000A94A 50BC5020 50C04110 00001821 502050C4 92002000 5850D028 47F0E004 070747F0 |&.&.&.......&.&Dk....&...0.....0|
      
      





または、さらに見つけることができます



  f1(int,char*) (DSA address 100202B0): UPSTACK DSA Saved Registers: GPR0..... 100087E8 GPR1..... 00000000 GPR2..... 00000000 GPR3..... 00000001 GPR4..... 1000A9A8 GPR5..... 100202B0 GPR6..... 1000AAAC GPR7..... 1000A0F0 GPR8..... 00000030 GPR9..... 80000000 GPR10.... 844EFCAA GPR11.... 846C69E8 GPR12.... 1001A7D0 GPR13.... 100202B0 GPR14.... 9000A9D8 GPR15.... 1000A930 GPREG STORAGE: Storage around GPR0 (100087E8) -0020 100087C8 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +0000 100087E8 1001C028 00000000 00000000 00000000 10017728 10017732 00000000 00000000 |................................| +0020 10008808 00000000 00000000 00000000 00000000 00000001 00000000 00000001 00000000 |................................| Storage around GPR1 (00000000) +0000 00000000 Inaccessible storage. +0020 00000020 Inaccessible storage. +0040 00000040 Inaccessible storage. Storage around GPR2 (00000000) +0000 00000000 Inaccessible storage. +0020 00000020 Inaccessible storage. +0040 00000040 Inaccessible storage. Storage around GPR3 (00000001) -0001 00000000 Inaccessible storage. +001F 00000020 Inaccessible storage. +003F 00000040 Inaccessible storage. Storage around GPR4 (1000A9A8) -0020 1000A988 05404140 401E07F4 90E5D00C 58E0D04C 4100E0A0 5500C314 4140F040 4720F014 |. . ..4.V.....<......C.. 0 ..0.| +0000 1000A9A8 5000E04C 9210E000 50D0E004 18DE5800 C1F45000 D098C050 00000021 5800D098 |&..<k...&.......A4&..q.&.......q| +0020 1000A9C8 58F04050 41300001 18131825 4DE0F010 47000008 18F35800 D0985000 C1F4180D |.0 &........(.0......3...q&.A4..|
      
      





レジスタリストはこの関数に関連している必要があることに注意してください。



レジスタの値を見ると、r2 = 0であるため、(0 + 0)になります。 これですべてが明らかになり、プログラムはアドレス0にデータを書き込もうとしていますが、アドレス0には読み取りも書き込みもアクセスできません。



すべてが、今ではソースコードでこれが起こっている理由、値が0を指している理由を見つけることが残っていますが、それは別のトピックです。



参照: z /アーキテクチャーの動作原理



All Articles