Once there, we could inspect the source code, show the state of program variables and try out arithmetic expressions in order to understand our bug. By switching on traps for floating point exceptions we were able to stop the program just as the bug occurred. By compiling the programs with debug info, GDB is able to work correctly and, apart from a few differences in how to breakpoint at startup, the process is largely the same as we’re used to. This was a quick intro into how to debug a less common (though still very popular) programming language. Time Travel Debugging Find and fix test failures in minutes - save time on debugging Linux C/C++ Learn more > Summary We’ve fixed our unwanted Infinity message! We’re now seeing the ratios of successive integers trending progressively closer to 1.0, as we would expect. If we fix this bug and re-run then we’ll see the following output: $>. The order of the variables in the division (see line 23) is wrong – we should be dividing d by e and not the other way around. Given the values of d and e, it looks like we are dividing by zero by mistake – GDB confirms that e/d gives the result inf, or infinity. For the purposes of this example, lets just inspect the values of the variables for mathematical errors: (gdb) p d In an interactive session, we might use the list command to check on the surrounding code. We’re in our divide function, called from our bugs routine. (arguments to _libc_start_main are omitted for brevity) We can use the debugger to find out where we are: (gdb) bt The debugger has now stopped on a floating point arithmetic exception – this is likely to be the source of our maths error. Program received signal SIGFPE, Arithmetic exception.Ġx0000000000400887 in divide (d=0, e=1) at bugs.f90:24 If we simply continue with execution, GDB will stop the program when a floating-point error occurs: (gdb) cont By default, GDB will stop when it sees signals that indicate errors – in C code we often we see this when a SIGSEGV occurs due to a pointer-related bug. Now we’ve recompiled to trap on floating point exceptions we will receive a SIGFPE if a floating point error happens. We could just do that until the error occurs – but it would be nice to jump to the exact moment of the floating point error we’re expecting. ![]() This is just as we’d expect from our C / C++ debugging experience – GDB is using the debug information from gfortran to step through lines of source code, so we can see how the state is changing. Now we can step through each line of Fortran source code by pressing n: (gdb) n a.outīreakpoint 1 at 0x4008c4: file bugs.f90, line 8. The reason we need to use MAIN_ instead of main (as we would usually use with C) is that main actually runs some startup code to set up the enviroment. To stop execution on the first line of our program we use b MAIN_. To start debugging our program we invoke gdb PROGRAM. Just as for a C program, we start our Fortran executable under control of the debugger. Lets build our executable with these new options: $> gfortran -g -ffpe-trap=zero,invalid,overflow,underflow bugs.f90 Debugging in GDB The -ffpe-trap compilation flag enables exception traps for the various floating point errors we can catch these with GDB to find the exact cause of our bug. The gfortran debug options can help us here. The Infinity output suggests that we have an error in our floating point maths, most likely a divide by zero. As with other compilers from the gcc family, we need to supply the -g flag to generate debug information. To diagnose this fault, we’re going to run the program under GDB. ![]() If we compile and run this code, we see the output contains unexpected text – the Infinity printed on the first line: $> gfortran bugs.f90 ![]() ! Calculate and print ratios of successive integers. ! Initialise c with successive integer values. It’s supposed to calculate the ratios between successive integers but it contains a bug: program bugs Today we’ll see a simple example of how we can debug Fortran programs, using features provided by GDB and gfortran. Debug info formats like DWARF, along with some language-specific extensions, allow GDB to support most of the commonly-used compiled languages. We are used to using GDB for debugging C and C++ but it can also be used to debug other languages including Fortran, D, Go and Ada. Jonathan Laver (engineer-in-training) and Mark Williamson (senior software engineer at Undo) write:
0 Comments
Leave a Reply. |