Oracle Solaris Studio 12.2: dbx コマンドによるデバッグ

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

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

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

Fortran のデバッグ

次のアドバイスと概要は、Fortran プログラムをデバッグするときに役立ちます。dbx を使用した Fortran OpenMP コードのデバッグについては、「イベントとの対話」を参照してください。

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

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

大文字

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

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

dbx のサンプルセッション

次の例では、サンプルプログラム 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

Proceduredbx のサンプルセッションの実行

  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
     Running: my_program
     stopped in MAIN at line 3 in file "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" is not defined in the current scope
    (dbx)

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

  6. 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 コマンドは、呼び出し元のプログラム中で、呼び出しのあとの最初の文にブレークポイントを設定します。

  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
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:

配列の操作

dbx が配列を認識し、配列を出力します。


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 のための配列断面化構文」を参照してください。

Fortran 95 割り当て可能配列

次の例は、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 は、Fortran 複合式も認識します。

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 構造型の表示

構造体、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 構造型へのポインタ

構造体、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
 )