Previous Next Contents Index Doc Set Home


Debugging Fortran Using dbx

18


This section introduces some dbx features likely to be used with Fortran. Sample requests to dbx are also included to provide you with assistance when debugging Fortran code using dbx.



Debugging Fortran

page 203

Debugging Segmentation Faults

page 208

Locating Exceptions

page 209

Tracing Calls

page 210

Working With Arrays

page 211

dbxShowing Intrinsic Functions

page 215

dbxShowing Complex Expressions

page 216

dbxShowing Logical Operators

page 217

Viewing Fortran 90 Derived Types

page 218

Pointer to Fortran 90 Derived Type

page 219

Fortran 90 Generic Functions

page 221

This chapter includes the following topics:


Debugging Fortran

The following tips and general concepts are provided to help you while debugging Fortran programs.

Current Procedure and File

During a debug session, dbx defines a procedure and a source file as current. Requests to set breakpoints and to print or set variables are interpreted relative to the current function and file. Thus, stop at 5 sets one of three different breakpoints, depending on whether the current file is a1.f, a2.f, or a3.f. dbx

Uppercase Letters (Fortran 77 only)

If your program has uppercase letters in any identifiers, dbx recognizes them. You need not provide case-sensitive or case-insensitive commands, as in some earlier versions. (The current release of f90 is case-insensitive.)

Fortran 77 and dbx must be in the same case-sensitive or case-insensitive mode:

If the source has a variable named LAST, then in dbx, both the print LAST or print last commands work. Both f77 and dbx consider LAST and last to be the same, as requested.

If the source has a variable named LAST and one named last, then in dbx, print LAST works, but print last does not work. Both f77 and dbx distinguish between LAST and last, as requested.


Note - File or directory names are always case-sensitive in dbx, even if you have set the dbxenv case insensitive environment attribute.

Optimized Programs

To debug optimized programs:

Main for debugging:

a1.f
	PARAMETER ( n=2 )
	REAL twobytwo(2,2) / 4 *-1 / 
	CALL mkidentity( twobytwo, n ) 
	PRINT *, determinant( twobytwo ) 
	END 

Subroutine for debugging:

a2.f
	SUBROUTINE mkidentity ( array, m ) 
	REAL array(m,m) 
	DO 90 i = 1, m 
		DO 20 j = 1, m 
		    IF ( i .EQ. j ) THEN 
			array(i,j) = 1. 
		    ELSE 
			array(i,j) = 0. 
		    END IF 
20		CONTINUE 
90	CONTINUE 
	RETURN 
	END 

Function for debugging:

a3.f
	REAL FUNCTION determinant ( a ) 
	REAL a(2,2) 
	determinant = a(1,1) * a(2,2) - a(1,2) / a(2,1) 
	RETURN 
	END 

Sample dbx Session

The following examples use a sample program called my_program.

1. Compile and link with the dbx-g flag. You can do this in one or two steps.

Compile and link in one step, with -g:

 demo% f77 -o my_program -g a1.f a2.f a3.f

Or, compile and link in separate steps:

 demo% f77 -c -g a1.f a2.f a3.f 
 demo% f77 -o my_program a1.o a2.o a3.o

2. Start dbx on the executable named my_program:

 demo% dbx my_program 
 Reading symbolic information... 

3. Set a simple breakpoint by typing stop in subnam, where subnam names a subroutine, function, or block data subprogram.

To stop at the first executable statement in a main program:

 (dbx) stop in MAIN 
 (2) stop in MAIN 

Although MAIN must be in uppercase, subnam can be uppercase or lowercase.

4. Enter the run command, which runs the program in the executable files named when you started dbx.

Run the program from within dbx:

 (dbx) run 
 Running: my_program 
 stopped in MAIN at line 3 in file "a1.f" 
 	3 		call mkidentity( twobytwo, n ) 

When the breakpoint is reached, dbx displays a message showing where it stopped--in this case, at line 3 of the a1.f file.

5. To print a value, enter the print command.

Print value of n:

 (dbx) print n
 n = 2 

Print the matrix twobytwo; the format may vary:

 (dbx) print twobytwo
 twobytwo =
    (1,1)       -1.0
    (2,1)       -1.0
    (1,2)       -1.0
    (2,2)       -1.0

Print the matrix array:

(dbx) print array 
dbx: "array" is not defined in the current scope
(dbx)

The print fails because array is not defined here--only in mkidentity.

6. To advance execution to the next line, enter the next command.

Advance execution to the next line:

(dbx) next 
stopped in MAIN at line 4 in file "a1.f" 
    4 			print *, determinant( twobytwo ) 
(dbx) print twobytwo 
twobytwo =
    (1,1)       1.0 
    (2,1)       0.0 
    (1,2)       0.0 
    (2,2)       1.0 
(dbx) quit 
demo%

The next command executes the current source line and stops at the next line. It counts subprogram calls as single statements.

Compare next with step. The step command executes the next source line or the next step into a subprogram. If the next executable source statement is a subroutine or function call, then:

7. To quit dbx, enter the quit command.

 (dbx)quit		
 demo%


Debugging Segmentation Faults

If a program gets a segmentation fault (SIGSEGV), it references a memory address outside of the memory available to it.

The most frequent causes for a segmentation fault are:

Using dbx to Locate Problems

Use dbxdbx to find the source code line where a segmentation fault occurred.

Use a program to generate a segmentation fault:

demo% cat WhereSEGV.f
	INTEGER a(5)
	j = 2000000 
	DO 9 i = 1,5 
		a(j) = (i * 10)
9	CONTINUE 
	PRINT *, a
	END 
demo%

Use dbx to find the line number of a dbxsegmentation fault:

demo% f77 -g -silent WhereSEGV.f
demo% a.out
*** TERMINATING a.out
*** Received signal 11 (SIGSEGV)
Segmentation fault (core dumped)
demo% dbx a.out
Reading symbolic information for a.out
program terminated by signal SEGV (segmentation violation)
(dbx) run
Running: a.out 
signal SEGV (no mapping at the fault address) 
in MAIN at line 4 in file "WhereSEGV.f"
    4                   a(j) = (i * 10)
(dbx)


Locating Exceptions

If a program gets an exception, there are many possible causes. One approach to locating the problem is to find the line number in the source program where the exception occurred, and then look for clues there.

Compiling with -ftrap =%all forces trapping on all exceptions.

Find where an exception occurred:

demo% cat wh.f
                 call joe(r, s)
                 print *, r/s
                 end
                 subroutine joe(r,s)
                 r = 12.
                 s = 0.
                 return
                 end
demo% f77 -g -o wh -ftrap=%all wh.f
wh.f:
 MAIN:
        joe:
demo% dbx wh
Reading symbolic information for wh
(dbx) catch FPE
(dbx) run
Running: wh
(process id 17970)
signal FPE (floating point divide by zero) in MAIN at line 2 in 
file "wh.f"
   2                     print *, r/s
(dbx)


Tracing Calls

Sometimes a program stops with a core dump, and you need to know the sequence of calls that brought it there. This sequence is called a stack trace.

The where command shows where in the program flow execution stopped and how execution reached this point--a stack trace of the called routines.

ShowTrace.f is a program contrived to get a core dump a few levels deep in the call sequence--to show a stack trace

Show the sequence of calls, starting at where the execution stopped:

 
 
 
 
 
 
 
 
 
Note the reverse order:
 
    MAIN called calc
calc called calcb.
 
Execution stopped, line 
23
calcB called from calc, 
line 9
calc called from MAIN, 
line 3
demo% f77 -silent -g ShowTrace.f 
demo% a.out
*** TERMINATING a.out
*** Received signal 11 (SIGSEGV)
Segmentation Fault (core dumped)
quil 174% dbx a.out
Reading symbolic information for a.out
...
(dbx) run 
Running: a.out 
(process id 1089)
signal SEGV (no mapping at the fault address) in calcb at line 23 
in file "ShowTrace.f"
   23                   v(j) = (i * 10)
(dbx) where -V
=>[1] calcb(v = ARRAY , m = 2), line 23 in "ShowTrace.f"
  [2] calc(a = ARRAY , m = 2, d = 0), line 9 in "ShowTrace.f"
  [3] MAIN(), line 3 in "ShowTrace.f"
(dbx)


Working With Arrays

dbxdbx recognizes arrays and can print them:

demo% dbx a.out 
Reading symbolic information... 
(dbx) list 1,25 
    1           DIMENSION IARR(4,4) 
    2           DO 90 I = 1,4 
    3                   DO 20 J = 1,4 
    4                           IARR(I,J) = (I*10) + J 
    5   20              CONTINUE 
    6   90      CONTINUE 
    7           END
(dbx) stop at 7 
(1) stop at "Arraysdbx.f":7
(dbx) run 
Running: a.out 



stopped in MAIN at line 7 in file "Arraysdbx.f" 
    7           END 
(dbx) print IARR 
iarr =
	(1,1) 11 
	(2,1) 21 
	(3,1) 31 
	(4,1) 41 
	(1,2) 12 
	(2,2) 22 
	(3,2) 32 
	(4,2) 42 
	(1,3) 13 
	(2,3) 23 
	(3,3) 33 
	(4,3) 43 
	(1,4) 14 
	(2,4) 24 
	(3,4) 34 
	(4,4) 44 
(dbx) print IARR(2,3) 
	iarr(2, 3) = 23   Order of user-specified subscripts ok 
(dbx) quit 

Fortran 90 Allocatable Arrays

The following example shows how to work with allocated arrays in dbx.




Alloc.f90
demo% f90 -g Alloc.f90
demo% dbx a.out
(dbx) list 1,99            
    1   PROGRAM TestAllocate
    2   INTEGER n, status 
    3   INTEGER, ALLOCATABLE :: buffer(:)
    4           PRINT *, 'Size?'
    5           READ *, n
    6           ALLOCATE( buffer(n), STAT=status )
    7           IF ( status /= 0 ) STOP 'cannot allocate buffer'
    8           buffer(n) = n
    9           PRINT *, buffer(n)
   10           DEALLOCATE( buffer, STAT=status)
   11   END












Unknown size at line 6









Known size at line 9




buffer(1000) holds 1000
(dbx) stop at 6 
(2) stop at "alloc.f90":6
(dbx) stop at 9
(3) stop at "alloc.f90":9
(dbx) run
Running: a.out 
(process id 10749)
 Size?
1000
stopped in main at line 6 in file "alloc.f90"
    6           ALLOCATE( buffer(n), STAT=status )
(dbx) whatis buffer
integer*4 , allocatable::buffer(:) 
(dbx) next        
continuing
stopped in main at line 7 in file "alloc.f90"
    7           IF ( status /= 0 ) STOP 'cannot allocate buffer'
(dbx) whatis buffer
integer*4 buffer(1:1000) 
(dbx) cont
stopped in main at line 9 in file "alloc.f90"
    9           PRINT *, buffer(n)
(dbx) print n     
n = 1000
(dbx) print buffer(n)
buffer(n) = 1000

Slicing Arrays

The syntax for Fortran array-slicing:

print arr-exp(first-exp:last-exp:stride-exp)



Variable
Description
Default

arr-exp

Expression that should evaluate to an array type

first-exp

First element printed

Lower bound

last-exp

Last element printed

Upper bound

stride-exp

Stride

1

To specify rows and columns:

demo% f77 -g -silent ShoSli.f 
demo% dbx a.out 
Reading symbolic information for a.out
(dbx) list 1,12 
	1 		INTEGER*4 a(3,4), col, row 
	2 		DO row = 1,3 
	3 			DO col = 1,4 
	4 			  a(row,col) = (row*10) + col 
	5 			END DO
	6 		END DO
	7 		DO row = 1, 3
	8   			 WRITE(*,'(4I3)') (a(row,col),col=1,4)
	9		END DO
	10		END
(dbx) stop at 7 
(1) stop at "ShoSli.f":7 
(dbx) run 
Running: a.out 
stopped in MAIN at line 7 in file "ShoSli.f" 
	7 		 DO row = 1, 3

Print row 3:






(dbx) print a(3:3,1:4)
'ShoSli'MAIN'a(3:3, 1:4) =
        (3,1)   31
        (3,2)   32
        (3,3)   33
        (3,4)   34
(dbx)




















Print column 4:






(dbx) print a(1:3,4:4)
'ShoSli'MAIN'a(3:3, 1:4) =
        (1,4)   14
        (2,4)   24
        (3,4)   34
(dbx)





















dbxShowing Intrinsic Functions

dbx recognizes Fortran intrinsic functions.

To show an intrinsic function in dbx:

demo% cat ShowIntrinsic.f
    INTEGER i
    i = -2
    END
(dbx) stop in MAIN
(2) stop in MAIN
(dbx) run
Running: shi
(process id 18019)
stopped in MAIN at line 2 in file "shi.f"
    2              i = -2
(dbx) whatis abs
Generic intrinsic function: "abs"
(dbx) print i
i = 0
(dbx) step
stopped in MAIN at line 3 in file "shi.f"
    3              end
(dbx) print i
i = -2
(dbx) print abs(1)
abs(i) = 2
(dbx)


dbxShowing Complex Expressions

dbx also recognizes Fortran complex expressions.

To show a complex expression in dbx:

demo% cat ShowComplex.f
    COMPLEX z
    z = ( 2.0, 3.0 )
    END
demo% f77 -g -silent ShowComplex.f
demo% dbx a.out
(dbx) stop in MAIN
(dbx) run
Running: a.out
(process id 10953)
stopped in MAIN at line 2 in file "ShowComplex.f"
    2       z = ( 2.0, 3.0 )
(dbx) whatis z
complex*8  z
(dbx) print z
z = (0.0,0.0)
(dbx) next
stopped in MAIN at line 3 in file "ShowComplex.f"
    3       END
(dbx) print z
z = (2.0,3.0)
(dbx) print z+(1.0,1.0)
z+(1,1) = (3.0,4.0)
(dbx) quit
demo%


dbxShowing Logical Operators

dbx can locate Fortran logical operators and print them.

To show logical operators in dbx:

demo% cat ShowLogical.f
        LOGICAL a, b, y, z
        a = .true.
        b = .false.
        y = .true.
        z = .false.
        END 
demo% f77 -g -silent ShowLogical.f
demo% dbx a.out
(dbx) list 1,9
    1           LOGICAL a, b, y, z 
    2           a = .true.
    3           b = .false.
    4           y = .true.
    5           z = .false.
    6           END 
(dbx) stop at 5
(2) stop at "ShowLogical.f":5
(dbx) run
Running: a.out
(process id 15394) 
stopped in MAIN at line 5 in file "ShowLogical.f"
    5           z = .false.
(dbx) whatis y
logical*4 y
(dbx) print a .or. y
a.OR.y = true
(dbx) assign z = a .or. y
(dbx) print z
z = true
(dbx) quit
demo%


Viewing Fortran 90 Derived Types

You can show structures--f90 derived types with dbx.

demo% f90 -g DebStruc.f90
demo% dbx a.out
(dbx) list 1,99              
    1   PROGRAM Struct ! Debug a Structure
    2      TYPE product
    3         INTEGER        id
    4         CHARACTER*16   name
    5         CHARACTER*8    model
    6         REAL           cost
    7         REAL           price
    8      END TYPE product
    9   
   10      TYPE(product) :: prod1
   11   
   12      prod1%id = 82
   13      prod1%name = "Coffee Cup"
   14      prod1%model = "XL"
   15      prod1%cost = 24.0
   16      prod1%price = 104.0
   17      WRITE ( *, * ) prod1%name
   18   END
(dbx) stop at 17
(2) stop at "Struct.f90":17
(dbx) run       
Running: a.out 
(process id 12326)
stopped in main at line 17 in file "Struct.f90"
   17      WRITE ( *, * ) prod1%name
(dbx) whatis prod1
product prod1
(dbx) whatis -t product
type product
    integer*4 id 
    character*16 name 
    character*8 model 
    real*4 cost 
    real*4 price 
end type product
(dbx) n 



(dbx) print prod1
prod1 = (
    id    = 82
    name = 'Coffee Cup'
    model = 'XL'
    cost = 24.0
    price = 104.0
)


Pointer to Fortran 90 Derived Type

You can show structures--f90 derived types, and pointers with dbx.






DebStruc.f90



Declare a derived type.



Declare prod1 and prod2 
targets.
Declare curr and prior 
pointers.

Make curr point to prod1.
Make prior point to 
prod1.
Initialize prior.

Set curr to prior.
Print name from curr and 
prior.
demo% f90 -o debstr -g DebStruc.f90
demo% dbx debstr
(dbx) stop in main
(2) stop in main
(dbx) list 1,99
    1   PROGRAM DebStruPtr! Debug structures & pointers
    2      TYPE product
    3         INTEGER        id
    4         CHARACTER*16   name
    5         CHARACTER*8    model
    6         REAL           cost
    7         REAL           price
    8      END TYPE product
    9   
   10      TYPE(product), TARGET :: prod1, prod2
   11      TYPE(product), POINTER :: curr, prior
   12   
   13      curr => prod2
   14      prior => prod1
   15      prior%id = 82
   16      prior%name = "Coffee Cup"
   17      prior%model = "XL"
   18      prior%cost = 24.0
   19      prior%price = 104.0
   20      curr = prior
   21      WRITE ( *, * ) curr%name, " ", prior%name
   22   END PROGRAM DebStruPtr
(dbx) stop at 21 
(1) stop at "DebStruc.f90":21
(dbx) run 
Running: debstr 



(process id 10972)
stopped in main at line 21 in file "DebStruc.f90" 
   21      WRITE ( *, * ) curr%name, " ", prior%name 
(dbx) print prod1 
 prod1 = (
	id = 82 
	name = "Coffee Cup" 
	model = "XL" 
	cost = 24.0 
	price = 104.0
) 

Above, dbx displays all fields of the derived type, including field names.

You can use structures--inquire about an item of an f90 derived type.

Ask about the variable

Ask about the type (-t)
(dbx) whatis prod1 
product prod1 
(dbx) whatis -t product 
type product
   integer*4 id 
   character*16 name 
   character*8 model 
   real cost 
   real price 
end type product 

To print a pointer:

dbx displays the contents 
of a pointer, which is an 
address. This address can 
be different with every 
run.
(dbx) print prior 
prior = (
    id    = 82
    name = 'Coffee Cup'
    model = 'XL'
    cost = 24.0
    price = 104.0
)


Fortran 90 Generic Functions

To work with Fortran 90 generic functions:

(dbx) list 1,99 
    1   MODULE cr 
    2     INTERFACE cube_root
    3       FUNCTION s_cube_root(x)
    4         REAL :: s_cube_root
    5         REAL, INTENT(IN) :: x
    6       END FUNCTION s_cube_root
    7       FUNCTION d_cube_root(x)
    8         DOUBLE PRECISION :: d_cube_root
    9         DOUBLE PRECISION, INTENT(IN) :: x
   10       END FUNCTION d_cube_root
   11     END INTERFACE
   12   END MODULE cr
   13   FUNCTION s_cube_root(x)
   14       REAL :: s_cube_root
   15       REAL, INTENT(IN) :: x
   16       s_cube_root = x ** (1.0/3.0)
   17   END FUNCTION s_cube_root
   18   FUNCTION d_cube_root(x)
   19       DOUBLE PRECISION :: d_cube_root
   20       DOUBLE PRECISION, INTENT(IN) :: x
   21       d_cube_root = x ** (1.0d0/3.0d0)
   22   END FUNCTION d_cube_root
   23   USE cr
   24     REAL :: x, cx
   25     DOUBLE PRECISION :: y, cy
   26     WRITE(*,"('Enter a SP number: ')")
   27     READ (*,*) x
   28     cx = cube_root(x)
   29     y = x
   30     cy = cube_root(y)
   31     WRITE(*,'("Single: ",F10.4, ", ", F10.4)') x, cx
   32     WRITE(*,'("Double: ",F12.6, ", ", F12.6)') y, cy
   33     WRITE(*,"('Enter a DP number: ')")
   34     READ (*,*) y
   35     cy = cube_root(y)
   36     x = y
   37     cx = cube_root(x)
   38     WRITE(*,'("Single: ",F10.4, ", ", F10.4)') x, cx
   39     WRITE(*,'("Double: ",F12.6, ", ", F12.6)') y, cy
   40     END

To use dbx with a generic function, cube root.










If asked "What is 
cube_root?", select one.






If asked for 
cube_root(8), dbx asks 
you to select which one.



If told to stop in 
cube_root, dbx asks you 
to select which one.








From inside s_cube_root,
show current value of x.
(dbx) stop at 26 
(2) stop at "Generic.f90":26
(dbx) run 
Running: Generic 
(process id 14633)
stopped in main at line 26 in file "Generic.f90"
   26     WRITE(*,"('Enter a SP number : ')")
(dbx) whatis cube_root
More than one identifier 'cube_root.'
Select one of the following names:
 1) `Generic.f90`cube_root s_cube_root ! real*4 s_cube_root
 2) `Generic.f90`cube_root s_cube_root ! real*8 d_cube_root
> 1
 real*4 function cube_root (x)
 (dummy argument) real*4 x
(dbx) print cube_root(8.0)
More than one identifier 'cube_root.'
Select one of the following names:
 1) `Generic.f90`cube_root ! real*4 s_cube_root
 2) `Generic.f90`cube_root ! real*8 d_cube_root
> 1
cube_root(8) = 2.0
(dbx) stop in cube_root
More than one identifier 'cube_root.'
Select one of the following names:
 1) `Generic.f90`cube_root ! real*4 s_cube_root
 2) `Generic.f90`cube_root ! real*8 d_cube_root
> 1
(3) stop in cube_root
(dbx) cont 
continuing
Enter a SP number: 
8
stopped in cube_root at line 16 in file "Generic.f90"
   16       s_cube_root = x ** (1.0/3.0)
(dbx) print x
x = 8.0




Previous Next Contents Index Doc Set Home