dbx コマンドによるデバッグ ホーム目次前ページへ次ページへ索引


第 16 章

dbx を使用した Fortran のデバッグ

この章では、Fortran で使用されることが多いいくつかの dbx 機能を紹介します。dbx を使用して Fortran コードをデバッグするときの助けになる、dbx に対する要求の例も示してあります。

この章は次の各節から構成されています。

Fortran のデバッグ

次のアドバイスと概要は、Fortran プログラムをデバッグするときに役立ちます。

カレントプロシージャとカレントファイル

デバッグセッション中、dbx は、1 つのプロシージャと 1 つのソースファイルをカレントとして定義します。ブレークポイントの設定要求と変数の出力または設定要求は、カレントの関数とファイルに関連付けて解釈されます。したがって、stop at 5 は、カレントファイルがどれであるかによって、3 つの異なるブレークポイントのうち 1 つを設定します。

大文字

プログラムのいずれかの識別子に大文字が含まれる場合、dbx はそれらを認識します。いくつかの旧バージョンの場合のように、大文字/小文字を区別するコマンド、または区別しないコマンドを指定する必要はありません。

FORTRAN 77、Fortran 95 と dbx は、大文字/小文字を区別するモードまたは区別しないモードのいずれかに統一する必要があります。

ソースに LAST という変数がある場合、dbx では、print LAST コマンドおよび print last コマンドはいずれも要求どおりに動作します。FORTRAN 77、Fortran 95 と dbx は、LASTlast を要求通り同じものとして扱います。

ソースに LAST という変数と last という変数がある場合、dbx では、print LAST コマンドは動作しますが、print last コマンドは動作しません。FORTRAN 77、Fortran 95 と dbx はいずれも、LASTlast を要求どおりに区別します。


注 - dbx input-_case_sensitive 環境属性の環境変数を false に設定しても、dbx ではファイル名またはディレクトリ名について、大文字/小文字を常に区別します。

最適化プログラム

最適化プログラムをデバッグするには、次のことを行ってください。

デバッグのメインプログラムは次のとおりです。

デバッグの主プログラム

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


dbx のサンプルセッション

以下の例では、上記のサンプルプログラム my_program を使用しています。

1. -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

2. 実行可能ファイル my_program について dbx を起動します。

 demo% dbx my_program
 Reading symbolic information... 

3. stop in subnam と入力して、最初の実行可能文の前にブレークポイントを設定する。subnam は、サブルーチン、関数、ブロックデータサブプログラムを示します。

main プログラム中の最初の実行可能文で停止します。

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

通常 MAIN は大文字ですが、subnam は大文字でも小文字でもかまいません。

4. run コマンドを入力して、dbx からプログラムを実行します。dbx の起動時に指定された実行可能ファイルの中で、プログラムが実行されます。

(dbx) run
実行中: my_program
MAIN で停止しました 行番号 3  ファイル "a1.f"
 	 3 	 	 call mkidentity( twobytwo, n ) 

ブレークポイントに到達すると、dbx はどこで停止したかを示すメッセージを表示します。上の例では、a1.f ファイルの行番号 3 で停止しています。

5. 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" が現在のスコープに定義されていません。
(dbx) 

ここで array は定義されていないため、出力は失敗します (mkidentity 内でのみ有効)。

6. 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) quit
demo%

next コマンドは現在のソース行を実行し、次のソース行で停止します。これは副プログラムの呼び出しを 1 つの文として数えます。
next コマンドと step コマンドを比較します。step コマンドは、ソースの次の行または副プログラムの次のステップを実行します。通常、次の実行可能ソース文がサブルーチンまたは関数呼び出しの場合、各コマンドは次の処理を行います。

7. quit コマンドを入力して、dbx を終了します。

 (dbx)quit		
 demo%

セグメント不正のデバッグ

プログラムでセグメント不正 (SIGSEGV) が発生するのは、プログラムが使用可能なメモリー範囲外のメモリーアドレスを参照したことを示します。

セグメント不正の主な原因を以下に示します。

dbx により問題を見つける方法

問題のあるソース行を見つけるには、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
セグメント例外
demo% dbx a.out
a.out の記号情報の読み込み中
シグナル SEGV でプログラムが停止しました (セグメント侵害)
(dbx) run
実行中: 
シグナル SEGV (障害アドレスにマッピングがありません)
    ファイル "WhereSEGV.f" の行番号 4 の MAIN で
    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
wh の記号情報を読み込み中
(dbx) catch FPE
(dbx) run
実行中: 
(プロセス ID 17970)
ファイル "wh.f" の行番号 2 の MAIN にシグナル FPE (ゼロで除算した浮動小
数点) 
   2                     print *, r/s
(dbx)

呼び出しのトレース

プログラムがコアダンプで終了したため、終了するまでの呼び出しシーケンスが必要な場合があるとします。このシーケンスをスタックトレースといいます。

where コマンドは、プログラムフローの実行が停止した位置、およびどのようにその位置に達したかを表示します。これを呼び出し先ルーチンのスタックトレースといいます。

ShowTrace.f は、呼び出しシーケンスでコアダンプを数レベル深くする、つまりスタックトレースを示すために考えられたプログラムです。

実行が停止した時点から呼び出しシーケンスを表示します。

順序が逆になっていることに注意してください。
MAINcalc を呼び出し、calccalcb を呼び出しています。




23 行目で実行が停止しました。



calcbcalc の 9 行目で呼び出されました。 calcMAIN の 3 行目で呼び出さ れました。
demo% f77 -silent -g ShowTrace.f 
demo% a.out
*** TERMINATING a.out
*** Received signal 11 (SIGSEGV)
Segmentation Fault (core dumped)
demo% dbx a.out
a.out のシンボル情報を読み込んでいます。
...
(dbx) run 
実行中: a.out 
(process id 1089)
シグナル SEGV (フォルトのアドレスにマッピングしていません) 関数 
calcb 行番号 23  ファイル "ShowTrace.f"
   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"
  [3] MAIN() 行番号 3 ファイル "ShowTrace.f"
(dbx)

配列の操作

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

Fortran の配列のスライスについては、「Fortran のための配列断面化構文」を参照してください。

Fortran 95 割り当て可能配列

次の例は、dbx で割り当て済み配列を処理する方法を示しています。





Alloc.f95






  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










行番号 6 に未知のサイズ







行番号 9 に既知のサイズ


バッファ (1000) に 1000 を格納
(dbx) stop at 6
(2) "alloc.f95":6で停止
(dbx) stop at 9
(3) "alloc.f95":9で停止
(dbx) run
実行中: a.out
(プロセス id 10749)
 サイズは ?
1000
MAIN で停止しました 行番号 6  ファイル "alloc.f95"
    6           ALLOCATE (buffer(n), STAT=status)
(dbx) whatis buffer
INTEGER*4 , allocatable::buffer(:)
(dbx) next
MAIN で停止しました 行番号 7  ファイル "alloc.f95"
    7           IF (status /= 0) STOP `cannot allocate buffer'
(dbx) whatis buffer
INTEGER*4  buffer(1:1000)
(dbx) cont
MAIN で停止しました 行番号 9  ファイル "alloc.f95"
    9           PRINT *,buffer(n)
(dbx) print n
n = 1000
(dbx) print buffer(n)
buffer(n) = 1000











行番号 6 に未知のサイズ







行番号 9 に既知のサイズ


バッファ (1000) に 1000 を格納
(dbx) stop at 6
(2) "alloc.f95":6で停止
(dbx) stop at 9
(3) "alloc.f95":9で停止
(dbx) run
実行中: a.out
(プロセス id 10749)
 サイズは ?
1000
MAIN で停止しました 行番号 6  ファイル "alloc.f95"
    6           ALLOCATE (buffer(n), STAT=status)
(dbx) whatis buffer
INTEGER*4 , allocatable::buffer(:)
(dbx) next
MAIN で停止しました 行番号 7  ファイル "alloc.f95"
    7           IF (status /= 0) STOP `cannot allocate buffer'
(dbx) whatis buffer
INTEGER*4  buffer(1:1000)
(dbx) cont
MAIN で停止しました 行番号 9  ファイル "alloc.f95"
    9           PRINT *,buffer(n)
(dbx) print n
n = 1000
(dbx) print buffer(n)
buffer(n) = 1000


組み込み関数

dbx は、Fortran の組み込み関数を認識します。

dbx での組み込み関数を示します。

(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 複合式も認識します。

dbx での複合式を示します。

demo% cat ShowComplex.f
      COMPLEX z
      z = (2.0, 3.0)
      END
demo% f95 -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 の論理演算子を配置し、出力することができます。

dbx での論理演算子を示します。

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

(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) "ShowLogical.f" で停止しました:

(dbx) run

実行中: a.out

(プロセス ID 15394)

MAIN で停止しました 行番号 5 ファイル "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 = false

(dbx) quit

demo%

Fortran 95 構造型の表示

構造体、Fortran 95 構造型を dbx で表示できます。

demo% f95 -g DebStruct.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 = "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.f95":17
(dbx) run


実行中: a.out
(プロセス id 23677)
MAIN で停止しました 行番号 17  ファイル "DebStruct.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
 Coffe  Cup
MAIN で停止しました 行番号 18  ファイル "DebStruct.f95"
   18   END
(dbx) print prod1
prod1 = (
    id    = 82
    name  = "Coffe  Cup      "
    model = "XL      "
    cost  = 24.0
    price = 104.0
)


Fortran 95 構造型へのポインタ

構造体、Fortran 95 構造型およびポインタを dbx で表示できます。

DebStruc.f95



構造型を宣言します。








prod1 および prod2 ターゲットを宣言します。(#10)
curr および prior ポインタを宣言します。(#11)
currprod2 を指すようにします。(#13)
demo% f95 -o debstr -g DebStruct.f95
demo% dbx debstr
debstr の読み込み中
ld.so.1 の読み込み中
 ......
(dbx) list 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
   11       TYPE(product), POINTER :: curr, prior
   12
   13       curr => prod2


priorprod1 を指すようにします。(#14)
prior を初期化します。(#15)

currprior に設定します。(#20)
curr および prior から名前を出力します。(#21)

   14       prior => prod1
   15       prior%id = 82
   16       prior%name = "Coffe  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
   23
(dbx) stop at 21
(2) stop at "DebStruct.f90":21
(dbx) run
実行中: debstr
(dbx) run
実行中: debstr
(プロセス id 23726)
MAIN で停止しました 行番号 21  ファイル "DebStruct.f95"
   21       WRITE (*, *) curr%name, " ", prior%name
(dbx) print prod1
prod1 = (
    id    = 82
    name  = "Coffe  Cup      "
    model = "XL      "
    cost  = 24.0
    price = 104.0
)

上記において dbx は、構造型のすべての要素を表示します。

構造体を使用して、Fortran 95 構造型の項目について照会できます。

変数について尋ねます。
型 (-t) について尋ねます。
(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 は、アドレスであるポインタの内容を表示します。このアドレスは、実行のたびに異なる場合があります。
(dbx) print prior
prior = (
    id    = 82
    name  = "Coffe  Cup      "
    model = "XL      "
    cost  = 24.0
    price = 104.0
)


サン・マイクロシステムズ株式会社
Copyright information. All rights reserved.
ホーム   |   目次   |   前ページへ   |   次ページへ   |   索引