Intel® Fortran Compiler 16.0 User and Reference Guide
The following sections provide sample programs that show the use of traceback to locate the cause of the error:
Note that the hex PC's and contents of registers displayed in these program outputs are meant as representative examples of typical output. The PC's will change over time, as the libraries and other tools used to create an image change.
In the following example, a READ statement creates an End-Of-File error, which the application has not handled:
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
The diagnostic output that results when this program is built with traceback enabled and linked against the single-threaded, shared Fortran run-time library on the IA-32 architecture platform is similar to the following:
forrtl: severe (24): end-of-file during read, unit 10, file E:\USERS\xxx.dat Image PC Routine Line Source libifcorert.dll 1000A3B2 Unknown Unknown Unknown libifcorert.dll 1000A184 Unknown Unknown Unknown libifcorert.dll 10009324 Unknown Unknown Unknown libifcorert.dll 10009596 Unknown Unknown Unknown libifcorert.dll 10024193 Unknown Unknown Unknown teof.exe 004011A9 AGAIN 21 teof.for teof.exe 004010DD GO 15 teof.for teof.exe 004010A7 WE 11 teof.for teof.exe 00401071 HERE 7 teof.for teof.exe 00401035 TEOF 3 teof.for teof.exe 004013D9 Unknown Unknown Unknown teof.exe 004012DF Unknown Unknown Unknown KERNEL32.dll 77F1B304 Unknown Unknown Unknown
The first line of the output is the standard Fortran run-time error message. What follows is the result of walking the call stack in reverse order to determine where the error originated. Each line of output represents a call frame on the stack. Since the application was compiled with the traceback option, the PCs that fall in Fortran code are correlated to their matching routine name, line number and source module. PCs that are not in Fortran code are not correlated and are reported as "Unknown."
The first five frames show the calls to routines in the Fortran run-time library (in reverse order). Since the application was linked against the single threaded, shared version of the library, the image name reported is either libifcore.so (Linux* OS and OS X*) or libifcorert.dll (Windows* OS). These are the run-time routines that were called to do the READ and upon detection of the EOF condition, were invoked to report the error. In the case of an unhandled I/O programming error, there will always be a few frames on the call stack down in run-time code like this.
The stack frame of real interest to the Fortran developer is the first frame in image teof.exe which shows that the error originated in the routine named AGAIN in source module teof.for at line 21. Looking in the source code at line 21, you can see the Fortran READ statement that incurred the end-of-file condition.
The next four frames show the trail of calls in the Fortran user code that led to the routine that got the error (TEOF->HERE->WE->GO->AGAIN).
Finally, the bottom three frames are routines which handled the startup and initialization of the program.
If this program had been linked against the single-threaded, static Fortran run-time library, the output would then look like:
forrtl: severe (24): end-of-file during read, unit 10, file E:\USERS\xxx.dat Image PC Routine Line Source teof.exe 004067D2 Unknown Unknown Unknown teof.exe 0040659F Unknown Unknown Unknown teof.exe 00405754 Unknown Unknown Unknown teof.exe 004059C5 Unknown Unknown Unknown teof.exe 00403543 Unknown Unknown Unknown teof.exe 004011A9 AGAIN 21 teof.for teof.exe 004010DD GO 15 teof.for teof.exe 004010A7 WE 11 teof.for teof.exe 00401071 HERE 7 teof.for teof.exe 00401035 TEOF 3 teof.for teof.exe 004202F9 Unknown Unknown Unknown teof.exe 00416063 Unknown Unknown Unknown KERNEL32.dll 77F1B304 Unknown Unknown Unknown
Notice that the initial five stack frames now show routines in image teof.exe, not libifcore.so (Linux OS and OS X) or libifcorert.dll (Windows OS). The routines are the same five run-time routines as previously reported for the shared library case but since the application was linked against the archive library libifcore.a (Linux OS and OS X) or the static Fortran run-time library libifcore.lib (Windows OS), the object modules containing these routines were linked into the application image (teof.exe). You can use a Generating Listing and Map Files to determine the locations of uncorrelated PCs.
Now suppose the application was compiled without traceback enabled and, once again, linked against the single-threaded, static Fortran library. The diagnostic output would appear as follows:
forrtl: severe (24): end-of-file during read, unit 10, file E:\USERS\xxx.dat Image PC Routine Line Source teof.exe 00406792 Unknown Unknown Unknown teof.exe 0040655F Unknown Unknown Unknown teof.exe 00405714 Unknown Unknown Unknown teof.exe 00405985 Unknown Unknown Unknown teof.exe 00403503 Unknown Unknown Unknown teof.exe 00401169 Unknown Unknown Unknown teof.exe 004010A8 Unknown Unknown Unknown teof.exe 00401078 Unknown Unknown Unknown teof.exe 00401048 Unknown Unknown Unknown teof.exe 0040102F Unknown Unknown Unknown teof.exe 004202B9 Unknown Unknown Unknown teof.exe 00416023 Unknown Unknown Unknown KERNEL32.dll 77F1B304 Unknown Unknown Unknown
Without the correlation information in the image that option traceback previously supplied, the Fortran run-time system cannot correlate PC's to routine name, line number, and source file. You can still use the Generating Listing and Map Files to at least determine the routine names and what modules they are in.
Remember that compiling with the traceback option increases the size of your application's image because of the extra PC correlation information included in the image. You can see if the extra traceback information is included in an image (checking for the presence of a .trace section) by entering:
objdump -h your_app.exe (Linux OS) otool -l your_app.exe (OS X) link -dump -summary your_app.exe (Windows OS)
Build your application with and without traceback and compare the file size of each image. Check the file size with a simple directory command.
For this simple teof.exe example, the traceback correlation information adds about 512 bytes to the image size. In a real application, this would probably be much larger. For any application, the developer must decide if the increase in image size is worth the benefit of automatic PC correlation or if manually correlating PC's with a map file is acceptable.
If an error occurs when traceback was requested during compilation, the run-time library will produce the correlated call stack display.
If an error occurs when traceback was disabled during compilation, the run-time library will produce the uncorrelated call stack display.
If you do not want to see the call stack information displayed, you can set the Supported Environment Variable FOR_DISABLE_STACK_TRACE to true. You will still get the Fortran run-time error message:
forrtl: severe (24): end-of-file during read, unit 10, file E:\USERS\xxx.dat
The following program generates a floating-point overflow exception when compiled with the fpe option value 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
Assume this program is compiled with the following:
Option fpe value 0
Option traceback
Option -O0 (Linux OS and OS X) or /Od (Windows OS)
On a system based on IA-32 architecture, the traceback output is similar to the following:
forrtl: error (72): floating overflow Image PC Routine Line Source ovf.exe 00401161 BELOW 29 ovf.f90 ovf.exe 0040113C OUT 24 ovf.f90 ovf.exe 0040111B WATCH 19 ovf.f90 ovf.exe 004010FA HEY 14 ovf.f90 ovf.exe 0040105B OVF 7 ovf.f90 ovf.exe 00432429 Unknown Unknown Unknown ovf.exe 00426C74 Unknown Unknown Unknown KERNEL32.dll 77F1B9EA Unknown Unknown Unknown
Notice that unlike the previous example of an unhandled I/O programming error, the stack walk can begin right at the point of the exception. There are no run-time routines on the call stack to dig through. The overflow occurs in routine BELOW at PC 00401161, which is correlated to line 29 of the source file ovf.f90.
When the program is compiled at a higher optimization level of O2, along with option fpe value 0 and the traceback option, the traceback output appears as follows:
forrtl: error (72): floating overflow Image PC Routine Line Source ovf.exe 00401070 OVF 29 ovf.f90 ovf.exe 004323E9 Unknown Unknown Unknown ovf.exe 00426C34 Unknown Unknown Unknown KERNEL32.dll 77F1B9EA Unknown Unknown Unknown
With O2, the entire program has been inlined.
The main program, OVF, no longer calls routine HEY. While the output is not quite what one might have expected intuitively, it is still entirely correct. You need to keep in mind the effects of compiler optimization when you interpret the diagnostic information reported for a failure in a release image.
If the same image were executed again, this time with the environment variable called TBK_ENABLE_VERBOSE_STACK_TRACE set to True, you would also see a dump of the exception context record at the time of the error. Here is an excerpt of how that might appear on a system using IA-32 architecture:
forrtl: error (72): floating overflow 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 ...
Consider the following example that shows how the traceback output might appear in a mixed Fortran/C application. The main program is a Fortran program named FPING. Program FPING triggers a chain of function calls which are alternately Fortran and C code. Eventually, the C routine named Unlucky is called, which produces a floating divide-by-zero error.
Source module FPING.FOR contains the Fortran function definitions, each of which calls a C routine from source module CPONG.C. The program FPING.FOR is compiled with the following options:
Option fpe value 0
Option traceback
Option -O0 (Linux OS and OS X) or /Od (Windows OS)
On the IA-32 architecture platform. the program traceback output resembles the following:
forrtl: error (73): floating divide by zero Image PC Routine Line Source fping.exe 00401161 Unknown Unknown Unknown fping.exe 004010DC DOWN4 58 fping.for fping.exe 0040118F Unknown Unknown Unknown fping.exe 004010B6 DOWN3 44 fping.for fping.exe 00401181 Unknown Unknown Unknown fping.exe 00401094 DOWN2 31 fping.for fping.exe 00401173 Unknown Unknown Unknown fping.exe 00401072 DOWN1 18 fping.for fping.exe 0040104B FPING 5 fping.for fping.exe 004013B9 Unknown Unknown Unknown fping.exe 004012AF Unknown Unknown Unknown KERNEL32.dll 77F1B304 Unknown Unknown Unknown
Notice that the stack frames contributed by Fortran routines can be correlated to a routine name, line number, and source module but those frames contributed by C routines cannot be correlated. Remember, even though the stack can be walked in reverse, and PCs reported, the information necessary to correlate the PC to a routine name, line number, and so on, is contributed to the image from the objects generated by the Fortran compiler. The C compiler does not have this capability. Also remember that you only get the correlation information if you specify the traceback option for your Fortran compiles.
The top stack frame cannot be correlated to a routine name because it is in C code. You can examine the map file for the application; if you do so, you will see that the reported PC, 00401161, is greater than the start of routine _Unlucky, but less than the start of routine _down1_C. This means that the error occurred in routine _Unlucky.
In a similar manner, the other PCs reported as "Unknown" can be correlated to a routine name using the map file.
When examining traceback output (or any type of diagnostic output, for that matter), it is important to keep in mind the effects of compiler optimization. The Fortran source module in the above example was built with optimization turned off. Look at the output when optimizations are enabled with the O2 option:
forrtl: error (73): floating divide by zero Image PC Routine Line Source fping.exe 00401111 Unknown Unknown Unknown fping.exe 0040109D DOWN4 58 fping.for fping.exe 0040113F Unknown Unknown Unknown fping.exe 00401082 DOWN3 44 fping.for fping.exe 00401131 Unknown Unknown Unknown fping.exe 0040106B DOWN2 31 fping.for fping.exe 00401123 Unknown Unknown Unknown fping.exe 00401032 FPING 18 fping.for fping.exe 00401369 Unknown Unknown Unknown fping.exe 0040125F Unknown Unknown Unknown KERNEL32.dll 77F1B304 Unknown Unknown Unknown
From the traceback output, it would appear that routine DOWN1 was never called. In fact, it has not been called. At the higher optimization level, the compiler has inlined function DOWN1 so that the call to routine down1_C is now made from FPING. The correlated line number still points to the correct line in the source code.
Finally, suppose the example Fortran code is redesigned with each of the Fortran routines split into separate source modules. Here is what the traceback output would look like with the redesigned code:
forrtl: error (73): floating divide by zero Image PC Routine Line Source fpingmain.exe 00401171 Unknown Unknown Unknown fpingmain.exe 004010ED DOWN4 12 fping4.for fpingmain.exe 0040119F Unknown Unknown Unknown fpingmain.exe 004010C1 DOWN3 11 fping3.for fpingmain.exe 00401191 Unknown Unknown Unknown fpingmain.exe 00401099 DOWN2 11 fping2.for fpingmain.exe 00401183 Unknown Unknown Unknown fpingmain.exe 00401073 DOWN1 11 fping1.for fpingmain.exe 0040104B FPING 5 fpingmain.for fpingmain.exe 004013C9 Unknown Unknown Unknown fpingmain.exe 004012BF Unknown Unknown Unknown KERNEL32.dll 77F1B304 Unknown Unknown Unknown
Notice that the line number and source file correlation information has changed to reflect the new design of the code.
Here are the sources used in the above examples:
************************************ FPING.FOR ************************************ program fping real*4 a,b a=-10.0 b=down1(a) end real*4 function down1(b) real*4 b !DIR$ IF DEFINED(_X86_) INTERFACE TO REAL*4 FUNCTION down1_C [C,ALIAS:'_down1_C'] (n) !DIR$ ELSE INTERFACE TO REAL*4 FUNCTION down1_C [C,ALIAS:'down1_C'] (n) !DIR$ ENDIF REAL*4 n [VALUE] END real*4 down1_C down1 = down1_C(b) end real*4 function down2(b) real*4 b [VALUE] !DIR$ IF DEFINED(_X86_) INTERFACE TO REAL*4 FUNCTION down2_C [C,ALIAS:'_down2_C'] (n) !DIR$ ELSE INTERFACE TO REAL*4 FUNCTION down2_C [C,ALIAS:'down2_C'] (n) !DIR$ ENDIF REAL*4 n [VALUE] END real*4 down2_C down2 = down2_C(b) end real*4 function down3(b) real*4 b [VALUE] !DIR$ IF DEFINED(_X86_) INTERFACE TO REAL*4 FUNCTION down3_C [C,ALIAS:'_down3_C'] (n) !DIR$ ELSE INTERFACE TO REAL*4 FUNCTION down3_C [C,ALIAS:'down3_C'] (n) !DIR$ ENDIF REAL*4 n [VALUE] END real*4 down3_C down3 = down3_C(b) end real*4 function down4(b) real*4 b [VALUE] !DIR$ IF DEFINED(_X86_) INTERFACE TO SUBROUTINE Unlucky [C,ALIAS:'_Unlucky'] (a,c) !DIR$ ELSE INTERFACE TO SUBROUTINE Unlucky [C,ALIAS:'Unlucky'] (a,c) !DIR$ ENDIF REAL*4 a [VALUE] REAL*4 c [REFERENCE] END real*4 a call Unlucky(b,a) down4 = a end ************************************ CPONG.C ************************************ #include <math.h> extern float __stdcall DOWN2 (float n); extern float __stdcall DOWN3 (float n); extern float __stdcall DOWN4 (float n); int Fact( int n ) { if (n > 1) return( n * Fact( n - 1 )); return 1; } void Pythagoras( float a, float b, float *c) { *c = sqrt( a * a + b * b ); } void Unlucky( float a, float *c) { float b=0.0; *c = a/b; } float down1_C( float a ) { return( DOWN2( a )); } float down2_C( float a ) { return( DOWN3( a )); } float down3_C( float a ) { return( DOWN4( a )); } ************************************ FPINGMAIN.FOR ************************************ program fping real*4 a,b a=-10.0 b=down1(a) end ************************************ FPING1.FOR ************************************ real*4 function down1(b) real*4 b !DIR$ IF DEFINED(_X86_) INTERFACE TO REAL*4 FUNCTION down1_C [C,ALIAS:'_down1_C'] (n) !DIR$ ELSE INTERFACE TO REAL*4 FUNCTION down1_C [C,ALIAS:'down1_C'] (n) !DIR$ ENDIF REAL*4 n [VALUE] END real*4 down1_C down1 = down1_C(b) end ************************************ FPING2.FOR ************************************ real*4 function down2(b) real*4 b [VALUE] !DIR$ IF DEFINED(_X86_) INTERFACE TO REAL*4 FUNCTION down2_C [C,ALIAS:'_down2_C'] (n) !DIR$ ELSE INTERFACE TO REAL*4 FUNCTION down2_C [C,ALIAS:'down2_C'] (n) !DIR$ ENDIF REAL*4 n [VALUE] END real*4 down2_C down2 = down2_C(b) end ************************************ FPING3.FOR ************************************ real*4 function down3(b) real*4 b [VALUE] !DIR$ IF DEFINED(_X86_) INTERFACE TO REAL*4 FUNCTION down3_C [C,ALIAS:'_down3_C'] (n) !DIR$ ELSE INTERFACE TO REAL*4 FUNCTION down3_C [C,ALIAS:'down3_C'] (n) !DIR$ ENDIF REAL*4 n [VALUE] END real*4 down3_C down3 = down3_C(b) end ************************************ FPING4.FOR ************************************ real*4 function down4(b) real*4 b [VALUE] !DIR$ IF DEFINED(_X86_) INTERFACE TO SUBROUTINE Unlucky [C,ALIAS:'_Unlucky'] (a,c) !DIR$ ELSE INTERFACE TO SUBROUTINE Unlucky [C,ALIAS:'Unlucky'] (a,c) !DIR$ ENDIF REAL*4 a [VALUE] REAL*4 c [REFERENCE] END real*4 a call Unlucky(b,a) down4 = a end