この章では、Fortran で使用されることが多いいくつかの dbx 機能を紹介します。dbx を使用して Fortran コードをデバッグするときの助けになる、dbx に対する要求の例も示してあります。
この章は次の各節から構成されています。
次のアドバイスと概要は、Fortran プログラムをデバッグするときに役立ちます。dbx を使用した Fortran OpenMP コードのデバッグについては、「イベントとの対話」を参照してください。
デバッグセッション中、dbx は、1 つのプロシージャと 1 つのソースファイルをカレントとして定義します。ブレークポイントの設定要求と変数の出力または設定要求は、カレントの関数とファイルに関連付けて解釈されます。したがって、stop at 5 は、カレントファイルがどれであるかによって、3 つの異なるブレークポイントのうち 1 つを設定します。
プログラムのいずれかの識別子に大文字が含まれる場合、dbx はそれらを認識します。いくつかの旧バージョンの場合のように、大文字/小文字を区別するコマンド、または区別しないコマンドを指定する必要はありません。
Fortran 95 と dbx は、大文字/小文字を区別するモードまたは区別しないモードのいずれかに統一する必要があります。
大文字/小文字を区別しないモードでコンパイルとデバッグを行うには、-U オプションを付けずにこれらの処理を行います。その場合、dbx input_case_sensitive 環境変数のデフォルト値は false になります。
ソースに LAST という変数がある場合、dbx では、print LAST コマンドおよび print last コマンドはいずれも要求どおりに動作します。Fortran 95 と dbx は、LAST と last を要求どおり同じものとして扱います。
大文字/小文字を区別するモードでコンパイルとデバッグを行うには、-U オプションを付けます。その場合、dbx input_case_sensitive 環境変数のデフォルト値は true になります。
ソースに LAST という変数と last という変数がある場合、dbx では、print last コマンドは動作しますが、print LAST コマンドは動作しません。Fortran 95 と dbx はいずれも、LAST と last を要求どおりに区別します。
dbx では、dbx input_case_sensitive 環境変数を false に設定しても、ファイル名またはディレクトリ名について、大文字/小文字を常に区別します。
次の例では、サンプルプログラム my_program を使用します。
デバッグのための主プログラム 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
|
-g オプションでコンパイルとリンクをします。
この処理は、まとめて 1 回または 2 回に分けて実行することができます。
-g フラグ付きコンパイルとリンクを 1 度にまとめて行います。
demo% f95 -o my_program -g a1.f a2.f a3.f |
コンパイルとリンクを分けて行います。
demo% f95 -c -g a1.f a2.f a3.f demo% f95 -o my_program a1.o a2.o a3.o |
実行可能ファイル my_program について dbx を起動します。
demo% dbx my_program Reading symbolic information… |
stop in subnam と入力して、簡単なブレークポイントを設定します。subnam は、サブルーチン、関数、ブロックデータサブプログラムを示します。
main プログラム中の最初の実行可能文で停止します。
(dbx) stop in MAIN (2) stop in MAIN |
通常 MAIN は大文字ですが、subnam は大文字でも小文字でもかまいません。
run コマンドを入力して、dbx からプログラムを実行します。dbx の起動時に指定された実行可能ファイルの中で、プログラムが実行されます。
(dbx) run
Running: my_program
stopped in MAIN at line 3 in file "a1.f"
3 call mkidentity( twobytwo, n )
|
ブレークポイントに到達すると、dbx はどこで停止したかを示すメッセージを表示します。前述の例では、a1.f ファイルの行番号 3 で停止しています。
print コマンドを使用して、値を出力します。
n の値を出力します。
(dbx) print n n = 2 |
マトリックス twobytwo を出力します。
(dbx) print twobytwo
twobytwo =
(1,1) -1.0
(2,1) -1.0
(1,2) -1.0
(2,2) -1.0
|
マトリックス array を出力します。
(dbx) print array dbx: "array" is not defined in the current scope (dbx) |
ここで array は定義されていないため、出力は失敗します (mkidentity 内でのみ有効)。
next コマンドを使用して、次の行に実行を進めます。
次の行に実行を進めます。
(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%
|
next コマンドは現在のソース行を実行し、次のソース行で停止します。これは副プログラムの呼び出しを 1 つの文として数えます。
next コマンドと step コマンドを比較します。step コマンドは、ソースの次の行または副プログラムの次のステップを実行します。通常、次の実行可能ソース文がサブルーチンまたは関数呼び出しの場合、各コマンドは次の処理を行います。
step コマンドは、副プログラムのソースの最初の文にブレークポイントを設定します。
next コマンドは、呼び出し元のプログラム中で、呼び出しのあとの最初の文にブレークポイントを設定します。
quit コマンドを入力して、dbx を終了します。
(dbx)quit demo% |
プログラムでセグメント不正 (SIGSEGV) が発生するのは、プログラムが使用可能なメモリー範囲外のメモリーアドレスを参照したことを示します。
セグメント不正の主な原因を次に示します。
配列インデックス名のつづりが間違っている。
呼び出し元のルーチンでは引数に REAL を使用しているが、呼び出し先のルーチンでは INTEGER が使われている。
配列インデックスの計算が間違っている。
呼び出し元ルーチンの引数が足りない。
ポインタを定義しないで使用している。
問題のあるソース行を見つけるには、dbx を使用してセグメント例外が発生したソースコード行を検出します。
プログラムを使ってセグメント例外を生成します。
demo% cat WhereSEGV.f
INTEGER a(5)
j = 2000000
DO 9 i = 1,5
a(j) = (i * 10)
9 CONTINUE
PRINT *, a
END
demo%
|
dbx を使用してセグメント例外が発生した行番号を検出します。
demo% f95 -g -silent WhereSEGV.f
demo% a.out
Segmentation fault
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)
|
プログラムが例外を受け取る原因は数多く考えられます。問題を見つける方法の 1 つとして、ソースプログラムで例外が発生した行番号を検出して調べる方法があります。
-ftrap=common によってコンパイルすると、すべての例外に対してトラップが強制的に行われます。
例外が発生した箇所を検索します。
demo% cat wh.f
call joe(r, s)
print *, r/s
end
subroutine joe(r,s)
r = 12.
s = 0.
return
end
demo% f95 -g -o wh -ftrap=common wh.f
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)
|
プログラムがコアダンプで終了したため、終了するまでの呼び出しシーケンスが必要な場合があるとします。このシーケンスをスタックトレースといいます。
where コマンドは、プログラムフローの実行が停止した位置、およびどのようにその位置に達したかを表示します。これを呼び出し先ルーチンの「スタックトレース」といいます。
ShowTrace.f は、呼び出しシーケンスでコアダンプを数レベル深くする、つまりスタックトレースを示すために考えられたプログラムです。
Note the reverse order: demo% f77 -silent -g ShowTrace.f demo% a.out MAIN called calc, calc called calcb. *** TERMINATING a.out *** Received signal 11 (SIGSEGV) Segmentation Fault (core dumped) quil 174% dbx a.out Execution stopped, line 23 Reading symbolic information for a.out ... (dbx) run calcB called from calc, line 9 Running: a.out (process id 1089) calc called from MAIN, line 3 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) Show the sequence of calls, starting at where the execution stopped: |
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 の配列のスライスについては、「Fortran のための配列断面化構文」を参照してください。
次の例は、dbx で割り当て済み配列を処理する方法を示しています。
demo% f95 -g Alloc.f95
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
(dbx) stop at 6
(2) stop at "alloc.f95":6
(dbx) stop at 9
(3) stop at "alloc.f95":9
(dbx) run
Running: a.out
(process id 10749)
Size?
1000
stopped in main at line 6 in file "alloc.f95"
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.f95"
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.f95"
9 PRINT *, buffer(n)
(dbx) print n
buffer(1000) holds 1000
n = 1000
(dbx) print buffer(n)
buffer(n) = 1000
|
dbx は、Fortran の組み込み関数 (SPARC プラットフォームおよび x86 プラットフォームのみ) を認識します。
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 での複合式を示します。
demo% cat ShowComplex.f
COMPLEX z
z = ( 2.0, 3.0 )
END
demo% f95 -g 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 で間隔式を表示するには、次のように入力します。
demo% cat ShowInterval.f95
INTERVAL v
v = [ 37.1, 38.6 ]
END
demo% f95 -g -xia ShowInterval.f95
demo% dbx a.out
(dbx) stop in MAIN
(2) stop in MAIN
(dbx) run
Running: a.out
(process id 5217)
stopped in MAIN at line 2 in file "ShowInterval.f95"
2 v = [ 37.1, 38.6 ]
(dbx) whatis v
INTERVAL*16 v
(dbx) print v
v = [0.0,0.0]
(dbx) next
stopped in MAIN at line 3 in file "ShowInterval.f95"
3 END
(dbx) print v
v = [37.1,38.6]
(dbx) print v+[0.99,1.01]
v+[0.99,1.01] = [38.09,39.61]
(dbx) quit
demo%
|
間隔式は、SPARC プラットフォームで実行するよう、Solaris x86 SSE/SSE2 Pentium 4 互換プラットフォームでは -xarch={sse|sse2}、x64 プラットフォームでは -xarch=amd64 を付けてコンパイルされたプログラムに対してのみサポートされます。
dbx は、Fortran の論理演算子を配置し、出力することができます。
dbx での論理演算子を示します。
demo% cat ShowLogical.f
LOGICAL a, b, y, z
a = .true.
b = .false.
y = .true.
z = .false.
END
demo% f95 -g 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%
|
構造体、Fortran 95 派生型を dbx で表示できます。
demo% f95 -g DebStruc.f95
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.f95":17
(dbx) run
Running: a.out
(process id 12326)
stopped in main at line 17 in file "Struct.f95"
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
)
|
構造体、Fortran 95 派生型およびポインタを dbx で表示できます。
demo% f95 -o debstr -g DebStruc.f95
demo% dbx debstr
(dbx) stop in main
(2) stop in main
(dbx) list 1,99
1 PROGRAM DebStruPtr! Debug structures & pointers
Declare a derived type.
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
Declare prod1 and prod2 targets.
10 TYPE(product), TARGET :: prod1, prod2
Declare curr and prior pointers.
11 TYPE(product), POINTER :: curr, prior
12
Make curr point to prod2.
13 curr => prod2
Make prior point to prod1.
14 prior => prod1
Initialize prior.
15 prior%id = 82
16 prior%name = "Coffee Cup"
17 prior%model = "XL"
18 prior%cost = 24.0
19 prior%price = 104.0
Set curr to prior.
20 curr = prior
Print name from curr and prior.
21 WRITE ( *, * ) curr%name, " ", prior%name
22 END PROGRAM DebStruPtr
(dbx) stop at 21
(1) stop at "DebStruc.f95":21
(dbx) run
Running: debstr
(process id 10972)
stopped in main at line 21 in file "DebStruc.f95"
21 WRITE ( *, * ) curr%name, " ", prior%name
(dbx) print prod1
prod1 = (
id = 82
name = "Coffee Cup"
model = "XL"
cost = 24.0
price = 104.0
)
|
前述において dbx は、構造型のすべての要素を表示します。
構造体を使用して、Fortran 95 派生型の項目について照会できます。
Ask about the variable
(dbx) whatis prod1
product prod1
Ask about the type (-t)
(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
)
|