この章では、Fortran で使用されることが多いいくつかの dbx 機能を紹介します。dbx を使用して Fortran コードをデバッグするときの助けになる、dbx に対する要求の例も示してあります。
この章は次の各節から構成されています。
次のアドバイスと概要は、Fortran プログラムをデバッグするときに役立ちます。
デバッグセッション中、dbx は、1 つのプロシージャと 1 つのソースファイルをカレントとして定義します。ブレークポイントの設定要求と変数の出力または設定要求は、カレントの関数とファイルに関連付けて解釈されます。したがって、stop at 5 は、カレントファイルが a1.f、a2.f、または a3.f のどれであるかによって、3 つの異なるブレークポイントのうち 1 つを設定します。
プログラムのいずれかの識別子に大文字が含まれる場合、dbx はそれらを認識します。いくつかの旧バージョンの場合のように、大文字/小文字を区別するコマンド、または区別しないコマンドを指定する必要はありません。
FORTRAN 77 と dbx は、大文字/小文字を区別するモードまたは区別しないモードのいずれかに統一する必要があります。
大文字/小文字を区別しないモードでコンパイルとデバッグを行うには、-U オプションを付けずにこれらの処理を行います。dbx のデフォルトは、dbxenv case insensitive になります。
ソースに LAST という変数がある場合、dbx では、print LAST コマンドおよび print last コマンドはいずれも要求どおりに動作します。
大文字/小文字を区別するモードでコンパイルとデバッグを行うには、-U オプションを使用します。dbx のデフォルトは dbxenv case sensitive になります。
ソースに LAST という変数と last という変数がある場合、dbx では、print LAST コマンドは動作しますが、print last コマンドは動作しません。FORTRAN 77 と dbx はいずれも、LAST と last を要求どおりに区別します。
dbxenv case insensitive 環境属性を設定しても、dbx ではファイル名またはディレクトリ名について、大文字/小文字を常に区別します。
最適化プログラムをデバッグするには、次のことを行ってください。
-g を付けて、-On を付けずにメインプログラムをコンパイルする。
適切な -On を付けて、プログラムのルーチンを 1 つおきにコンパイルする。
dbx のもとで実行を開始する。
デバッグしたいルーチンに対して fix -g any.f を使用する。ただし、-On は付けない。
コンパイルされたルーチンに対して continue を使用する。
デバッグの主プログラム
PARAMETER ( n=2 )
REAL twobytwo(2,2) / 4 *-1 /
CALL mkidentity( twobytwo, n )
PRINT *, determinant( twobytwo )
END
デバッグのサブルーチン
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
デバッグの関数
REAL FUNCTION determinant ( a )
REAL a(2,2)
determinant = a(1,1) * a(2,2) - a(1,2) / a(2,1)
RETURN
END
以下の例では、上記のサンプルプログラム my_program を使用しています。
-g フラグを付けてコンパイルとリンクを行います。次のように 、1 度にまたは 2 度に分けて実行できます。
-g フラグ付きコンパイルとリンクを 1 度にまとめて行います。
demo% f77 -o my_program -g a1.f a2.f a3.f
demo% f77 -c -g a1.f a2.f a3.f demo% f77 -o my_program a1.o a2.o a3.o
実行可能ファイル my_program について dbx を起動します。
demo% dbx my_program my_program の読み込み中 ld.so.1 の読み込み中 libF77.so.4 の読み込み中 libM77.so.2 の読み込み中 libsunmath.so.1 の読み込み中 libm.so.1 の読み込み中 libc.so.1 の読み込み中 libdl.so.1 の読み込み中 libc_psr.so.1 の読み込み中
stop in subnam と入力して、最初の実行可能文の前にブレークポイントを設定する。subnam は、サブルーチン、関数、ブロックデータサブプログラムを示します。
(dbx) stop in MAIN (2) stop in MAIN
通常 MAIN は大文字ですが、subnam は大文字でも小文字でもかまいません。
run コマンドを入力して、dbx からプログラムを実行します。dbx の起動時に指定された実行可能ファイルの中で、プログラムが実行されます。
(dbx) run
実行中: my_program
(プロセス id 23395)
mb.so.1 の読み込み中
wcwidth.so.1 の読み込み中
MAIN で停止しました 行番号 3 ファイル "a1.f"
3 call mkidentity( twobytwo, n )
(dbx)
ブレークポイントに到達すると、dbx はどこで停止したかを示すメッセージを表示します。上の例では、a1.f ファイルの行番号 3 で停止しています。
print コマンドを使用して、値を出力します。
(dbx) print n n = 2
(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" は スコープ`my_program`a1.f`MAIN` に定義されていません dbx: 詳しくは 'help scope' をご覧ください (dbx)
ここで array は定義されていないため、出力は失敗します (mkidentity 内でのみ有効)。
next コマンドを使用して、次の行に実行を進めます。
(dbx) next
MAIN で停止しました 行番号 4 ファイル "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)
next コマンドは現在のソース行を実行し、次のソース行で停止します。これは副プログラムの呼び出しを 1 つの文として数えます。
next と step コマンドを比較します。step コマンドは、ソースの次の行または副プログラムの次のステップを実行します。通常、次の実行可能ソース文がサブルーチンまたは関数呼び出しの場合、各コマンドは次の処理を行います。
step コマンドは、副プログラムのソースの最初の文にブレークポイントを設定します。
next コマンドは、呼び出し元のプログラム中で、呼び出しの後の最初の文にブレークポイントを設定します。
(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% f77 -g -silent WhereSEGV.f
demo% ./a.out
*** TERMINATING ./a.out
*** Received signal 11 SIGSEGV
Segmentation fault (core dumped)
demo% dbx a.out
a.out の読み込み中
rtld /usr/lib/ld.so.1 の読み込み中
libF77.so.3 の読み込み中
libsunmath.so.1 の読み込み中
libm.so.1 の読み込み中
libc.so.1 の読み込み中
libdl.so.1 の読み込み中
(dbx) run
実行中: a.out
(プロセス id 2273)
mb.so.1 の読み込み中
wcwidth.so.1 の読み込み中
シグナル SEGV (フォルトのアドレスにマッピングしていません) 関数 MAIN 行番号 4 ファイル "WhereSEGV.f"
4 a(j) = (i * 10)
(dbx)
プログラムが例外を受け取る原因は数多く考えられます。問題を見つける方法の 1 つとして、ソースプログラムで例外が発生した行番号を検出して調べる方法があります。
-ftrap =%all によってコンパイルすると、すべての例外に対してトラップが強制的に行われます。
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
wh の読み込み中
ld.so.1 の読み込み中
.....
(dbx) catch FPE
(dbx) run
実行中: wh
(プロセス id 23464)
mb.so.1 の読み込み中
wcwidth.so.1 の読み込み中
シグナル FPE (ゼロによる浮動小数点徐算) 関数 MAIN 行番号 2 ファイル "wh.f"
2 print *, r/s
(dbx)
プログラムがコアダンプで終了したため、終了するまでの呼び出しシーケンスが必要な場合があるとします。このシーケンスをスタックトレースといいます。
where コマンドは、プログラムフローの実行が停止した位置、およびどのようにその位置に達したかを表示します。これを呼び出し先ルーチンのスタックトレースといいます。
ShowTrace.f は、呼び出しシーケンスでコアダンプを数レベル深くする、つまりスタックトレースを示すために考えられたプログラムです。
demo% f77 -silent -g ShowTrace.f (注 1) demo% a.out *** TERMINATING a.out *** Received signal 11 (SIGSEGV) (注 2) Segmentation Fault (core dumped) demo% dbx a.out a.out のシンボル情報を読み込んでいます。 ... (dbx) run 実行中: a.out (process id 1089) シグナル SEGV (フォルトのアドレスにマッピングしていません) 関数 calcb 行番号 23 ファイル "ShowTrace.f" (注 3) 23 v(j) = (i * 10) (dbx) where -V =>[1] calcb(v = ARRAY , m = 2) 行番号 23 ファイル "ShowTrace.f" [2] calc(a = ARRAY , m = 2, d = 0) 行番号 9 ファイル "ShowTrace.f" (注 4) [3] MAIN() 行番号 3 ファイル "ShowTrace.f" (dbx)
注 1: 順序が逆になっていることに注意してください。
注 2: MAIN が calc を呼び出し、calc が calcb を呼び出しています。
注 3: 23 行目で実行が停止しました。
注 4: calc が MAIN の 3 行目で呼び出さ れました。
dbx が配列を認識し、配列を出力します。
demo% dbx a.out
a.out の読み込み中
ld.so.1 の読み込み中
......
(dbx) list
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
(2) stop at "Arraysdbx.f":7
(dbx) run
実行中: a.out
(プロセス id 23495)
mb.so.1 の読み込み中
wcwidth.so.1 の読み込み中
MAIN で停止しました 行番号 7 ファイル "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
(dbx) quit
次の例は、dbx で割り当て済み配列を処理する方法を示しています。
demo% f90 -g Alloc.f90
demo% dbx a.out
a.out の読み込み中
ld.so.1 の読み込み中
...... (注 1)
(dbx) list 1,$
1 PROGRAM TestAlocate
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.f90":6
(dbx) stop at 9
(3) stop at "Alloc.f90":9
(dbx) run
実行中: a.out
(プロセス id 23512)
Size?
1000
MAIN で停止しました 行番号 6 ファイル "Alloc.f90" (注 2)
6 ALLOCATE (buffer(n), STAT=status)
(dbx) whatis buffer
INTEGER*4 , allocatable::buffer(:)
(dbx) next
MAIN で停止しました 行番号 7 ファイル "Alloc.f90"
7 IF (status /= 0) STOP `cannot allocate buffer'
(dbx) whatis buffer
INTEGER*4 buffer(1:1000)
(dbx) cont
MAIN で停止しました 行番号 9 ファイル "Alloc.f90" (注 3)
9 PRINT *,buffer(n)
(dbx) print n
n = 1000
(dbx) print buffer(n)
buffer(n) = 1000 (注 4)
注 1: Alloc.f90
注 2: 行番号 6 ではサイズは未知
注 3: 行番号 9 ではサイズは未知
注 4: buffer (1000)
print arr-exp(first-exp :last-exp:stride-exp )
|
変数 |
説明 |
デフォルト |
|---|---|---|
|
arr-exp |
1 つの配列型に評価される式 |
|
|
first-exp |
出力される最初の要素 |
配列の下限 |
|
last-exp |
出力される最後の要素 |
配列の上限 |
|
stride-exp |
刻み幅 |
1 |
demo% f77 -g -silent ShoSli.f
demo% dbx a.out
a.out の読み込み中
ld.so.1 の読み込み中
......
(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
(2) stop at "ShoSli.f":7
(dbx) run
実行中: a.out
(プロセス id 23521)
mb.so.1 の読み込み中
wcwidth.so.1 の読み込み中
MAIN で停止しました 行番号 7 ファイル "ShoSli.f"
7 do row = 1, 3
(dbx)
(dbx) print a(3:3,1:4)
a(3:3, 1:4) =
(3,1) 31
(3,2) 32
(3,3) 33
(3,4) 34
(dbx)
(dbx) print a(1:3,4:4)
a(3:3, 1:4) =
(1,4) 14
(2,4) 24
(3,4) 34
(dbx)
dbx は、Fortran の組み込み関数を認識します。
(dbx) list 1,$
1 INTEGER i
2 i = -2
3 END
(dbx) stop in MAIN
(2) stop in MAIN
(dbx) run
実行中: a.out
(プロセス id 23536)
mb.so.1 の読み込み中
wcwidth.so.1 の読み込み中
MAIN で停止しました 行番号 2 ファイル "ShowIntrinsic.f"
2 i = -2
(dbx) whatis abs
Generic intrinsic function: "abs"
(dbx) print i
i = 0
(dbx) step
MAIN で停止しました 行番号 3 ファイル "ShowIntrinsic.f"
3 END
(dbx) print i
i = -2
(dbx) print abs(i)
abs(i) = 2
(dbx) quit
demo%
dbx は、Fortran 複合式も認識します。
demo% cat ShowComplex.f
COMPLEX z
z = (2.0, 3.0)
END
demo% f77 -g -silent ShowComplex.f
demo% dbx a.out
a.out の読み込み中
ld.so.1 の読み込み中
......
(dbx) stop in MAIN
(2) stop in MAIN
(dbx) run
実行中: a.out
(プロセス id 23567)
mb.so.1 の読み込み中
wcwidth.so.1 の読み込み中
MAIN で停止しました 行番号 2 ファイル "ShowComplex.f"
2 z = (2.0, 3.0)
(dbx) whatis z
complex*8 z
(dbx) print z
z = (0.0,0.0)
(dbx) next
MAIN で停止しました 行番号 3 ファイル "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
dbx は、Fortran の論理演算子を配置し、出力することができます。
demo% cat ShowLogical1.f
LOGICAL a, b, y, z
a = .true.
b = .false.
y = .true.
z = .false.
END
demo% f77 -g -silent ShowLogical1.f
demo% dbx a.out
a.out の読み込み中
ld.so.1 の読み込み中
......
(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 "ShowLogical1.f":5
(dbx) run
実行中: a.out
(プロセス id 23587)
mb.so.1 の読み込み中
wcwidth.so.1 の読み込み中
MAIN で停止しました 行番号 5 ファイル "ShowLogical1.f"
5 z = .false.
(dbx) whatis y
logical*4 y
(dbx) print a .or. y
a.OR.y = true
(dbx) print z
z = false
(dbx) quit
demo%
demo% f90 -g DebStruct.f90
demo% dbx a.out
a.out の読み込み中
ld.so.1 の読み込み中
......
(dbx) list 1,$
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 = "Coffe 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 "DebStruct.f90":17
(dbx) run
実行中: a.out
(プロセス id 23677)
MAIN で停止しました 行番号 17 ファイル "DebStruct.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
Coffe Cup
MAIN で停止しました 行番号 18 ファイル "DebStruct.f90"
18 END
(dbx) print prod1
prod1 = (
id = 82
name = "Coffe Cup "
model = "XL "
cost = 24.0
price = 104.0
)
構造体、f90 構造型およびポインタを dbx で表示できます。
demo% f90 -o debstr -g DebStruct.f90
demo% dbx debstr
debstr の読み込み中
ld.so.1 の読み込み中
......
(dbx) list 1,$ (注 1)
1 Program DebStruPtr ! Debug a Structure & pointer
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 (注 2)
11 TYPE(product), POINTER :: curr, prior (注 3)
12
13 curr => prod2 (注 4)
14 prior => prod1 (注 5)
15 prior%id = 82 (注 6)
16 prior%name = "Coffe Cup"
17 prior%model = "XL"
18 prior%cost = 24.0
19 prior%price = 104.0
20 curr = prior (注 7)
21 WRITE (*, *) curr%name, " ", prior%name (注 8)
22 END PROGRAM DebStruPtr
23
(dbx) stop at 21
(2) stop at "DebStruct.f90":21
(dbx) run
実行中: debstr
(dbx) run
実行中: debstr
(プロセス id 23726)
MAIN で停止しました 行番号 21 ファイル "DebStruct.f90"
21 WRITE (*, *) curr%name, " ", prior%name
(dbx) print prod1
prod1 = (
id = 82
name = "Coffe Cup "
model = "XL "
cost = 24.0
price = 104.0
)
注 1: 構造型を宣言します。
注 2: prod1 および prod2 ターゲットを宣言します。(#10)
注 3: curr および prior ポインタを宣言します。(#11)
注 4: curr が prod2 を指すようにします。(#13)
注 5: prior が prod1 を指すようにします。(#14
注 6: prior を初期化します。(#15
注 7: curr を prior に設定します。(#20)
注 8: curr および prior から名前を印刷します。(#21)
上記において dbx は、構造型のすべての要素を表示します。
構造体を使用して、f90 構造型の項目について照会できます。
(dbx) whatis prod1 (注 1)
product prod1
(dbx) whatis -t product (注 2)
type product
INTEGER*4 id
character*16 name
character*8 model
REAL*4 cost
REAL*4 price
end type product
注 1: 変数について尋ねます。
注 2: 型 (-t) について尋ねます。
(dbx) print prior (注 1)
prior = (
id = 82
name = "Coffe Cup "
model = "XL "
cost = 24.0
price = 104.0
)
注 1: dbx は、アドレスであるポインタの内容を表示します。このアドレスは、実行のたびに異 なる場合があります。