インテル® Fortran コンパイラー 19.0 デベロッパー・ガイドおよびリファレンス
このセクションでは、トレースバックを使用してエラーの原因を特定する方法を示すサンプルプログラムについて説明します。
これらのプログラム出力で表示される 16 進の PC とレジスターの内容は、一般的な出力の代表例です。PC は、実行ファイルの作成に使用したライブラリーとほかのツールの変更に伴って変更されます。
次の READ 文は、アプリケーションが処理しないファイル終了エラーを発生させます。
program teof
integer*4 i,res
i=here( )
end
integer*4 function here( )
here = we( )
end
integer*4 function we( )
we = go( )
end
integer*4 function go( )
go = again( )
end
integer*4 function again( )
integer*4 a
open(10,file='xxx.dat',form='unformatted',status='unknown')
read(10) a
again=a
end
このプログラムをインテル® 64 アーキテクチャー・ベースのプラットフォームでトレースバックを有効にし、最適化を無効にしてビルドし、Fortran 共有ランタイム・ライブラリーとリンクすると、診断出力は次のようになります。
forrtl: 致命的なエラー (24): 読み取り中にファイルの最後に達しました。ユニット 10、ファイル E:\USERS\xxx.dat Image PC Routine Line Source libifcorert.dll 000007FED2B232D9 Unknown Unknown Unknown libifcorert.dll 000007FED2B6CEE0 Unknown Unknown Unknown teof.exe 000000013F931193 AGAIN 17 teof.f90 teof.exe 000000013F93109B GO 12 teof.f90 teof.exe 000000013F931072 WE 9 teof.f90 teof.exe 000000013F931049 HERE 6 teof.f90 teof.exe 000000013F93101E MAIN__ 3 teof.f90 teof.exe 000000013F96ADCE Unknown Unknown Unknown teof.exe 000000013F96B64C Unknown Unknown Unknown kernel32.dll 0000000076CC59BD Unknown Unknown Unknown ntdll.dll 0000000076EFA2E1 Unknown Unknown Unknown
最適化を無効 (Windows*: /Od、Linux* および macOS*: -O0) にしない場合、プロシージャーのインライン展開によりコールスタックがコラプスされ、問題を特定するのが困難です。
出力の最初の行は、標準の Fortran ランタイム・エラー・メッセージです。その後には、エラーの発生場所を特定するために、コールスタックを逆向きに巡回した結果が表示されています。個々の出力行は、スタック上の 1 つのコールフレームを表しています。アプリケーションは traceback オプションを指定してコンパイルされているため、Fortran コード内の PC は、対応するルーチン名、行番号、およびソースモジュールと関係付けられています。Fortran コード中にない PC は関係付けられずに、"Unknown" とレポートされています。
最初の 2 つのフレームは、Fortran ランタイム・ライブラリー中のルーチンへの呼び出しを (逆順で) 示しています。アプリケーションは共有ライブラリーにリンクされているため、レポートされる実行ファイルの名前は libifcore.so (Linux* および macOS*) または libifcorert.dll (Windows*) となっています。これらは、READ を実行するために、およびファイル終了 (EOF) 条件の検出時にエラーをレポートするのに呼び出されたランタイムルーチンです。未処理の I/O のプログラミング・エラーでは、コールスタック上にはこのようなランタイムコードのフレームが常にいくつか存在します。
Fortran 開発者にとって真に重要なスタックフレームは、実行ファイル teof.exe 内の最初のフレームです。ここでは、ソースモジュール teof.f90 の 17 行目の AGAIN という名前のルーチンでエラーが発生したことが示されています。ソースコードの 21 行目で、ファイル終了条件を引き起こした Fortran の READ 文があることが分かります。
次の 4 つのフレームは、エラーを発生させたルーチンに至る、Fortran コード内の一連の呼び出しを示しています (TEOF→HERE→WE→GO→AGAIN)。
最後の 4 つのフレームは、プログラムの起動と初期化を処理したルーチンです。
このプログラムが、スタティック Fortran ランタイム・ライブラリーにリンクされていた場合、出力は次のようになります。
forrtl: 致命的なエラー (24): 読み取り中にファイルの最後に達しました。ユニット 10、ファイル E:\USERS\xxx.dat Image PC Routine Line Source teof.exe 000000013F941FFB Unknown Unknown Unknown teof.exe 000000013F9380A0 Unknown Unknown Unknown teof.exe 000000013F931193 AGAIN 17 teof.f90 teof.exe 000000013F93109B GO 12 teof.f90 teof.exe 000000013F931072 WE 9 teof.f90 teof.exe 000000013F931049 HERE 6 teof.f90 teof.exe 000000013F93101E MAIN__ 3 teof.f90 teof.exe 000000013F96ADCE Unknown Unknown Unknown teof.exe 000000013F96B64C Unknown Unknown Unknown kernel32.dll 0000000076CC59BD Unknown Unknown Unknown ntdll.dll 0000000076EFA2E1 Unknown Unknown Unknown
最初の 2 つのスタックフレームは、libifcore.so (Linux* および macOS*) または libifcorert.dll (Windows*) ではなく実行ファイル teof.exe 中のルーチンを示しています。ルーチンは共有ライブラリーの場合にレポートされた 2 つのランタイムルーチンと同じものですが、アプリケーションはアーカイブ・ライブラリー libifcore.a (Linux* および macOS*) またはスタティック Fortran ランタイム・ライブラリー libifcore.lib (Windows*) にリンクされたので、これらのルーチンを含むオブジェクト・モジュールはアプリケーション・イメージ (teof.exe) にリンクされています。「リストとマップファイルの生成」を使用して、関係付けられていない PC の場所を決定することができます。
アプリケーションがトレースバックを有効にしないでコンパイルされ、スタティック Fortran ライブラリーにリンクされた場合、診断出力は次のようになります。
forrtl: 致命的なエラー (24): 読み取り中にファイルの最後に達しました。ユニット 10、ファイル E:\USERS\xxx.dat Image PC Routine Line Source teof.exe 000000013F851FFB Unknown Unknown Unknown teof.exe 000000013F8480A0 Unknown Unknown Unknown teof.exe 000000013F841193 Unknown Unknown Unknown teof.exe 000000013F84109B Unknown Unknown Unknown teof.exe 000000013F841072 Unknown Unknown Unknown teof.exe 000000013F841049 Unknown Unknown Unknown teof.exe 000000013F84101E Unknown Unknown Unknown teof.exe 000000013F87ADCE Unknown Unknown Unknown teof.exe 000000013F87B64C Unknown Unknown Unknown kernel32.dll 0000000076CC59BD Unknown Unknown Unknown ntdll.dll 0000000076EFA2E1 Unknown Unknown Unknown
イメージに traceback によって提供された関係情報がないため、Fortran ランタイムシステムは PC をルーチン名、行番号、およびソースファイルに関係付けることができません。この場合でも、「リストとマップファイルの生成」を使用すれば、少なくともルーチン名と、それが含まれるモジュールを決定することはできます。
traceback オプションを指定してコンパイルを行うと、実行ファイルに追加の PC の関係情報が含まれるので、実行ファイルのサイズが大きくなることに注意してください。実行ファイルに追加のトレースバック情報が含まれているかどうか (.trace セクションが存在するかどうか) を調べるには、次のように入力してください。
objdump -h your_app.exe ! Linux*
otool -l your_app.exe ! macOS*
link -dump -summary your_app.exe ! Windows*
traceback を指定した場合と指定しない場合でアプリケーションをビルドして、生成される実行ファイルのサイズを比較してみてください。単純なディレクトリー・コマンドでファイルのサイズを確認できます。
この teof.exe の例では、トレースバックの関係情報が含まれることで実行ファイルのサイズが 512 バイト大きくなっています。実際のアプリケーションでは、これよりもはるかに大きくなるでしょう。開発者は、個々のアプリケーションについて、実行ファイルのサイズが大きくなっても PC の関係付けを自動的に行うほうが良いのか、それとも PC とマップファイルの関係付けを手作業で行うほうが良いのかを判断しなければなりません。
コンパイル時にトレースバックを有効にした場合、エラーが発生すると、ランタイム・ライブラリーは関係情報を含むコールスタック表示を出力します。
コンパイル時にトレースバックを無効にした場合、エラーが発生すると、ランタイム・ライブラリーは関係情報を含まないコールスタック表示を出力します。
コールスタック情報を表示したくない場合、サポートされる環境変数 FOR_DISABLE_STACK_TRACE を true に設定します。ただし、この場合でも次の Fortran のランタイム・エラー・メッセージは表示されます。
forrtl: 致命的なエラー (24): 読み取り中にファイルの最後に達しました。ユニット 10、ファイル E:\USERS\xxx.dat
次のプログラムは、fpe 0 を指定してコンパイルすると、浮動小数点オーバーフロー例外が生成されます。
program ovf
real*4 a
a=1e37
do i=1,10
a=hey(a)
end do
print *, 'a= ', a
end
real*4 function hey(b)
real*4 b
hey = watch(b)
end
real*4 function watch(b)
real*4 b
watch = out(b)
end
real*4 function out(b)
real*4 b
out = below(b)
end
real*4 function below(b)
real*4 b
below = b*10.0e0
end
このプログラムは、以下のオプションを指定してコンパイルされると仮定しています。
オプション fpe 0
オプション traceback
オプション -O0 (Linux* および macOS*) または /Od (Windows*)
IA-32 アーキテクチャー・ベースのシステムでは、トレースバック出力は次のようになります。
forrtl: エラー (72): 浮動小数点オーバーフロー Image PC Routine Line Source ovf.exe 001211A3 _BELOW 23 ovf.f90 ovf.exe 0012116F _OUT 19 ovf.f90 ovf.exe 0012113D _WATCH 15 ovf.f90 ovf.exe 0012110B _HEY 11 ovf.f90 ovf.exe 0012104E _MAIN__ 5 ovf.f90 ovf.exe 0015B31F Unknown Unknown Unknown ovf.exe 0015BADD Unknown Unknown Unknown kernel32.dll 7515338A Unknown Unknown Unknown ntdll.dll 770E9902 Unknown Unknown Unknown ntdll.dll 770E98D5 Unknown Unknown Unknown
前に示した、処理されない I/O のプログラミング・エラーの例と同様に、例外が発生した場所からスタック巡回を開始することができます。ランタイムルーチンはコールスタック上にはありません。 オーバーフローは、ソースファイル ovf.f90 の 23 行目に関係付けられている BELOW ルーチンの PC 001211A3 で発生しています。
これよりも高い最適化レベル O2 で fpe 0 オプションと traceback オプションを指定してプログラムをコンパイルすると、トレースバック出力は次のようになります。
forrtl: エラー (72): 浮動小数点オーバーフロー Image PC Routine Line Source ovf.exe 00AE1059 _MAIN__ 7 ovf.f90 ovf.exe 00B1B75F Unknown Unknown Unknown ovf.exe 00B1BADD Unknown Unknown Unknown kernel32.dll 7515338A Unknown Unknown Unknown ntdll.dll 770E9902 Unknown Unknown Unknown ntdll.dll 770E98D5 Unknown Unknown Unknown
O2 では、プログラム全体がインライン展開されます。
メインプログラム OVF は、HEY ルーチンを呼び出さなくなっています。この出力は直観的に予想されるものとはかなり異なりますが、依然として完全に正しいものです。リリース版実行ファイルでの実行の失敗に関する診断情報を解釈するときには、コンパイラーの最適化の効果を念頭に置く必要があります。
環境変数 TBK_ENABLE_VERBOSE_STACK_TRACE を true に設定して、同じ実行ファイルをもう一度実行すると、エラーの発生時に例外コンテキスト・レコードのダンプも表示されます。IA-32 アーキテクチャー・ベースのシステムではどのように表示されるかを次に抜粋します。
forrtl: エラー (72): 浮動小数点オーバーフロー Hex Dump Of Exception Record Context Information: Exception Context: Processor Control and Status Registers. EFlags: 00010212 CS: 0000001B EIP: 00401161 SS: 00000023 ESP: 0012FE38 EBP: 0012FE60 Exception Context: Processor Integer Registers. EAX: 00444488 EBX: 00000009 ECX: 00444488 EDX: 00000002 ESI: 0012FBBC EDI: F9A70030 Exception Context: Processor Segment Registers. DS: 00000023 ES: 00000023 FS: 00000038 GS: 00000000 Exception Context: Floating Point Control and Status Registers. ControlWord: FFFF0262 ErrorOffset: 0040115E DataOffset: 0012FE5C StatusWord: FFFFF8A8 ErrorSelector: 015D001B DataSelector: FFFF0023 TagWord: FFFF3FFF Cr0NpxState: 00000000 Exception Context: Floating Point RegisterArea. RegisterArea[00]: 4080BC143F4000000000 RegisterArea[10]: F7A0FFFFFFFF77F9D860 RegisterArea[20]: 00131EF0000800060012 RegisterArea[30]: 00000012F7C002080006 RegisterArea[40]: 02080006000000000000 RegisterArea[50]: 0000000000000012F7D0 RegisterArea[60]: 00000000000000300000 RegisterArea[70]: FBBC000000300137D9EF ...