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.
This chapter includes the following topics:
The following tips and general concepts are provided to help you while debugging Fortran programs.
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.
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:
To compile and debug in case-insensitive mode, do so without the -U option. The default then is dbxenv case insensitive.
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.
To compile and debug in case-sensitive mode, use --U. The default is then dbxenv case sensitive.
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.
File or directory names are always case-sensitive in dbx, even if you have set the dbxenv case insensitive environment attribute.
To debug optimized programs:
Compile the main program with --g but with no --On.
Compile every other routine of the program with the appropriate -On.
Start the execution under dbx.
Use fix -g any.f on the routine you want to debug, but no -On.
Use continue with that routine compiled.
a1.f PARAMETER ( n=2 ) REAL twobytwo(2,2) / 4 *-1 / CALL mkidentity( twobytwo, n ) PRINT *, determinant( twobytwo ) END
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
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
The following examples use a sample program called my_program.
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
Start dbx on the executable named my_program:
demo% dbx my_program Reading symbolic information...
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.
Type 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.
To print a value, type the print command.
(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
(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.
To advance execution to the next line, type 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:
step sets a breakpoint at the first source statement of the subprogram.
next sets the breakpoint at the first source statement after the call, but still in the calling program.
To quit dbx, type the quit command.
(dbx)quit demo%
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:
An array index is outside the declared range.
The name of an array index is misspelled.
The calling routine has a REAL argument, which the called routine has as INTEGER.
An array index is miscalculated.
The calling routine has fewer arguments than required.
A pointer is used before it is defined.
Use dbx 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 dbx segmentation 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)
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)
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.
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)
dbx 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
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
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
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 in range, also first element printed |
Lower bound |
last-exp |
Last element in range, but may not be last element printed if stride is greater than 1 |
Upper bound |
stride-exp |
Stride |
1 |
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
(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)
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)
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%
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%
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 )
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
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 )
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