dbx コマンドによるデバッグ

第 3 章 コードの表示

プログラムが停止するたびに dbx が表示するソースコードは、その停止位置に対応するコードです。また、プログラムが停止するたびに、dbx は現在の関数の値をプログラムが停止した関数の値に再設定します。プログラムの停止後、その停止場所以外の関数やファイルを一時的に表示することができます。

この章では、デバッグセッション中に dbx がどのようにコードを参照し、関数やシンボルを検索するかを説明します。また、コマンドを使用して、プログラムの停止位置とは別の場所のコードを一時的に表示したり、識別子、型、クラスの宣言を調べたりする方法も説明します。

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

コード位置へのマッピング

dbx は、プログラムに関連するソースファイルおよびオブジェクトコードファイルの位置を知っていなければなりません。オブジェクトファイルのデフォルトディレクトリは、プログラムが最後にリンクされたときにオブジェクトファイルがあったディレクトリです。ソースファイルのデフォルトディレクトリは、最後のコンパイル時にそれらが存在したディレクトリです。ソースファイルまたはオブジェクトファイルを移動したか、またはそれらを新しい位置にコピーした場合は、プログラムを再リンクするか、または新しい位置に変更してから、デバッグを行う必要があります。

ソースファイルまたはオブジェクトファイルを移動した場合、その新しい位置を検索パスに追加できます。pathmap コマンドは、ファイルシステムの現在のディレクトリと実行可能イメージ内の名前のマッピングを作成します。このマッピングは、ソースパスとオブジェクトファイルパスに適用されます。

ディレクトリ from から ディレクトリ to への新しいマッピングを確立するには、次のように入力します。


pathmap [-c] from to

-c を使用すると、このマッピングは、現在の作業ディレクトリにも適用されます。

pathmap コマンドは、ホストによってベースパスの異なる、自動マウントされた明示的な NFS マウントファイルシステムを扱う場合でも便利です。-c は、現在の作業ディレクトリが自動マウントされたファイルシステム上で不正確なオートマウンタが原因で起こる問題を解決する場合に使用してください。

/tmp_mnt/ のマッピングはデフォルトで存在します。

停止位置とは別の部分のコードを表示する

プログラムを実行していないときはいつでも、プログラム内の停止位置とは別の部分を表示できます。プログラムに含まれるすべての関数またはファイルを表示できます。

ファイルの内容を表示する

dbx がプログラムの一部として認識していれば、どのファイルでもその内容を表示できます (モジュールまたはファイルが -g オプションでコンパイルされていない場合でも可能です)。ファイルを表示した場合、関数は変更されません。ファイルの内容を表示するためには、次のように入力します。


file filename

ファイルコマンドを単独で使用すると、現在表示中のファイル名が表示されます


file

dbx は、行番号を指定しないと、最初の行からファイルを表示します。


file filename ; list line_number

関数を表示する

func コマンドを使用すると、関数を表示することができます。コマンド func に続けて、関数名を入力します。func コマンドを単独で使用すると、現在表示中の関数が表示されます。次の例を示します。


(dbx) func adjust_speed

あいまいな関数名をリストから選択する (C++)

C++ の場合、あいまいな名前または多重定義されている関数名を指定してメンバー関数を表示しようとすると、多重定義されているというメッセージが表示され、指定された名前を持つ関数のリストが示されます。

指定の関数があいまいな場合は、表示したい関数の番号を入力します。関数が属している特定クラスを知っている場合は、次のように入力することができます。


(dbx) func block::block

複数存在する場合の選択

同じスコープレベルから複数のシンボルにアクセスできる場合、dbx は、あいまいさについて報告するメッセージを出力します。


(dbx) func main
(dbx) which block::block
識別子 'block' が複数あります
以下の名前から 1 つ選択してください:
 0)	取り消し
 1)	`Blocks`block.cc`block::block(void)
 2)	`Blocks`block.cc`block::block(char*, int, int, const point&, 
	load_bearing_block*)
>

which コマンドのコンテキストでシンボル名のリストから特定のシンボルを選んでも、dbx またはプログラムの状態には影響しません。いずれにせよ、どのシンボルを選んでも名前を表示するだけです。

which コマンドは、dbx がどのシンボルを検索するかを前もって示すものです。あいまいな名前を指定して、多重定義されていると表示された場合は、該当する複数の名前のうちのどれを使用するかがまだ特定されていません。リストに表示されている名前から 1 つを選んでください。

ソースリストの出力

list コマンドは、ファイルまたは関数のソースリストを出力するために使用します。filename を指定した場合は filename の先頭を表示、number を指定した場合は現在のファイルの number 行目を表示、function を指定した場合はその関数を表示します。


list [-i | -instr] [+] [-] number [ function | filename ]

呼び出しスタックの操作によってコードを表示する

プロセスが存在するときにコードを表示する方法としては、さらに「呼び出しスタックを操作する」方法があります。この方法では、スタック操作コマンドを使用して現在スタック上にある関数を表示します。

スタックを操作すると、現在の関数とファイルは、スタック関数を表示するたびに変更されます。停止位置は、スタックの「底」にあるものと考えられます。したがって、そこから離れるには up コマンドを使用します。つまり、main 関数などに向かって移動します。

スコープ決定演算子を使用してシンボルを修飾する

func または file を使用する場合、スコープ決定演算子を使用して、ターゲットとして指定する関数の名前を修飾することができます。

dbx では、シンボルを修飾するためのスコープ決定演算子として、逆引用符演算子 (`) と C++ のスコープ決定演算子 (::) 、ブロック局所演算子 (:lineno) を使用することができます。これらの演算子は別々に、ときには同時に使用します。

停止位置以外の部分のコードを表示するためにファイルや関数の名前を修飾するだけでなく、スコープ外の変数や式の出力や表示を行なったり、型やクラスの宣言を表示したり (whatis コマンド) する場合にも、シンボルを修飾することが必要です。シンボルの修飾規則はすべての場合で同じです。この節で示す規則は、あらゆる種類のシンボル名の修飾に適用されます。

逆引用符演算子

逆引用符演算子 (`) は、大域スコープの変数を検索するために使用できます。


(dbx) print `item

プログラムでは、同じ関数名を 2 つの異なるファイル (またはコンパイルモジュール) で使用できます。この場合、dbx に対しても関数名を修飾して、表示する関数を認識させる必要があります。ファイル名に関連して関数名を修飾するには、汎用逆引用符 (`) スコープ決定演算子を使用してください。


(dbx) func `file_name`function_name

コロンを重ねたスコープ決定演算子 (C++)

次のような名前を持つ C++ のメンバー関数またはトップレベル関数を修飾するときには、コロンを 2 つ重ねた演算子 (::) を使用します。

多重定義された関数名を修飾できます。多重定義された関数名を修飾しないと、dbx は多重定義表示リストを自動的に表示して、表示する関数を選択するよう要求します。関数のクラス名がわかっている場合は、それを二重コロンのスコープ決定演算子とともに使用して、名前を修飾できます。


(dbx) func class::function_name  (args) 

たとえば、hand がクラス名で draw が関数名の場合は、次のようになります。


(dbx) func hand::draw 

ブロックローカル演算子

ブロックローカル演算子 (:lineno) は、逆引用符演算子と組み合わせて使用します。これは、必要なインスタンスを参照する式の行番号を識別します。

次の例では、:230 がブロックローカル演算子です。


(dbx) stop in `animate.o`change_glyph:230`item

リンカー名

dbx は、(C++ のようにさまざまな名前が混在するため)リンカー名ごとにシンボルを探すよう特別な構文を使用します。シンボル名の接頭辞として # 記号を付け、Korn シェルで $ 記号の前にエスケープ文字 ¥ を使用します。


(dbx) stop in #.mul
(dbx) whatis #¥$FEcopyPc
(dbx) print `foo.c`#staticvar

スコープ決定パス

dbx 固有コマンドにターゲットとして指定されたシンボルが検索を必要とするものである場合、dbx はそのシンボルを次の順序で検索します。

  1. 最初に現在の関数のスコープ内で検索を行います。プログラムが、入れ子になったブロックで停止した場合はそのブロック内で検索した後、その関数によって宣言されている外側のすべてのブロックのスコープ内で検索します。

  2. C++ の場合のみ : 現在の関数クラスのクラスメンバーとその基底クラス。

  3. すぐ外側にある「コンパイル単位」: 一般に、現在の関数が含まれているファイル。

  4. ロードオブジェクトのスコープ。

  5. 大域的スコープ。

  6. 上記のすべてで該当するシンボルが見つからなかった場合は非公開変数、すなわちファイル内で「静的」な変数または関数と見なします。dbxenv による scope_look_aside の設定値によっては、コンパイル単位ごとにファイル静的シンボルを検索することもできます。

dbx はこの検索パスで最初に見つけたシンボルを使用します。変数が見つからなかった場合はエラーを報告します。

シンボルを検索する

同じ名前が多くの場所で使用されたり、プログラム内の異なる種類の構成要素を参照したりすることがあります。dbx コマンド whereis は、特定の名前を持つすべてのシンボルの完全修飾名 (すなわち位置) のリストを表示します。一方、dbx コマンド which は、特定の名前を dbx コマンドのターゲットとしたときに、実際に使用されるシンボルを示します。

シンボルの出現を出力する

指定シンボルの出現すべてのリストを出力するには、whrereis symbol を使用します。ここで、symbol は任意のユーザー定義識別子にすることができます。次に例を示します。


(dbx) whereis table
前方:   `Blocks`block_draw.cc `table
関数:   `Blocks`block.cc`table::table(char*, int, int, const
         point&)
クラス: `Blocks`block.cc`class table
クラス: `Blocks`main.cc`class table
変数:   `libc.so.1`hsearch.c`table

この出力には、プログラムがシンボルを定義する読み込み可能オブジェクトの名前が、各オブジェクトの構成要素の種類 (クラス、関数、または変数) とともに示されます。

dbx シンボルテーブルの情報は必要に応じて読み取られるため、whereis コマンドは、すでに読み込まれているシンボルの出現についてしか出力しません。デバッグセッションが長くなると、出現のリストは大きくなります。

実際に使用されるシンボルを調べる

which コマンドにより、特定の名前を (完全に修飾しないで) デバッグコマンドのターゲットとして指定したときにどのシンボルが使用されるかを前もって調べることができます。


(dbx) func
wedge::wedge(char*, int, int, const point&, load_bearing_block*)
(dbx) which draw
`block_draw.cc`wedge::draw(unsigned long)

which コマンドに指定したシンボル名が局所的スコープにない場合、スコープ決定パスで検索が行われます。決定パスで最初に見つかった名前の完全修飾名が示されます。

決定パスに含まれる任意の場所で、同じスコープの該当するシンボルが複数見つかった場合、あいまいであることを示すメッセージが表示されます。


(dbx) which fid
`example`file1.c`fid
`example`file2.c`fid

dbx は、あいまいなシンボル名をリストで示し、多重定義であることを表示します。which コマンドのコンテキストでシンボル名のリストから特定のシンボルを選んでも、dbx またはプログラムの状態には影響しません。ほとんどの場合、どのシンボルを選んでも名前が表示されるだけです。

which コマンドは、あるシンボル (この例の場合は block) をコマンド (たとえば、print コマンド) のターゲットにした場合に何が起こるかを前もって示すものです。あいまいな名前を指定して、多重定義が表示された場合は、該当する複数の名前のうちのどれを使用するかがまだ特定されていません。リストに表示されている名前から 1 つを選んでください。

変数、メンバー、型、クラスを調べる

dbx コマンド whatis は、識別子、構造体、型、C++ のクラス、式の型の宣言または定義を出力します。検査できる識別子には、変数、関数、フィールド、配列、列挙定数が含まれます。

識別子の宣言を出力するには、次のように入力します。


(dbx ) whatis identifier

識別名は、必要に応じてファイルおよび関数情報によって修飾します。

メンバー関数を出力するには、次のように入力します。


(dbx) whatis block::draw
void block::draw(unsigned long pw);
(dbx) whatis table::draw
void table::draw(unsigned long pw);
(dbx) whatis block::pos
class point *block::pos();
Notice that table::pos is inherited from block:
(dbx) whatis table::pos
class point *block::pos();

データメンバーを出力するには、次のように入力します。


(dbx) whatis block::movable
int movable;

変数を指定すると、その変数の型が示されます。


(dbx) whatis the_table
class table *the_table;

フィールドを指定すると、そのフィールドの型が示されます。


(dbx) whatis the_table->draw
void table::draw(unsigned long pw);

メンバー関数で停止したときは、this ポインタを調べることができます。この例の場合、whatis からの出力は、コンパイラがレジスタに this 変数を自動的に割り当てたことを示しています。


(dbx) stop in brick::draw
(dbx) cont
// expose the blocks window (if exposed, hide then expose) to force program to hit the breakpoint.
(dbx) where 1
brick::draw(this = 0x48870, pw = 374752)、line 124 in
     “block_draw.cc”
(dbx) whatis this
class brick *this;

型およびクラスの定義を調べる

型または C++ のクラスの宣言を出力するには次のようにします。


(dbx) whatis -t type_or_class_name 

whatis コマンドには、継承されたメンバーを表示するための -r (再帰) オプションが用意されています。このオプションを指定すると、指定したクラス class_name の宣言とともに、そのクラスが親クラスから継承したメンバーが表示されます。


(dbx)  whatis -t -r class_name

whatis -r による出力は、クラス階層と各クラスのサイズによって長くなることがあります。出力の先頭には、階層の最も上にあるクラスから継承されたメンバーのリストが示されます。メンバーのリストは、コメント行によって親クラスごとに分けられます。

ここに、2 つの例を示します。table クラスは、load_bearing_block クラスの子クラスの 1 つです。また、load_bearing_block クラスは、block の子クラスです。

-r を指定しないと、table クラスで宣言されているメンバーが示されます。


(dbx) whatis -t class table
class table : public load_bearing_block {
public:
    table::table(char *name, int w, int h, const class point &pos);
    virtual char *table::type();
    virtual void table::draw(unsigned long pw);
};

次に、子クラスが継承するメンバーを表示するために whatis -r がその子クラスで使用された場合の結果を示します。


(dbx) whatis -t -r class table
class table : public load_bearing_block {
public:
  /* 基底 class table::load_bearing_block::block から */
  block::block();
  block::block(char *name, int w, int h, const class point &pos, class load_bearing_block *blk);
    virtual char *block::type();
    char *block::name();
    int block::is_movable();
//  exampleprotected から削除されたいくつかのメンバー:
    char *nm;
    int movable;
    int width;
    int height;
    class point  position;
    class load_bearing_block *supported_by;
    Panel_item panel_item;
    /* 基底 class table::load_bearing_block から */
public:
 load_bearing_block::load_bearing_block();
 load_bearing_block::load_bearing_block(char *name, int w, int h,
const class point &pos, class load_bearing_block *blk);
    virtual int load_bearing_block::is_load_bearing();
    virtual class list *load_bearing_block::supported_blocks();
    void load_bearing_block::add_supported_block(class block &b);
    void load_bearing_block::remove_supported_block(class block &b);
    virtual void load_bearing_block::print_supported_blocks();
    virtual void load_bearing_block::clear_top();
 virtual void load_bearing_block::put_on(class block &object);
    class point load_bearing_block::get_space(class block &object);
    class point load_bearing_block::find_space(class block &object);
    class point load_bearing_block::make_space(class block &object);
protected:
    class list *support_for;
    /* class table から */
public:
    table::table(char *name, int w, int h, const class point &pos);
    virtual char *table::type();
    virtual void table::draw(unsigned long pw);
};

自動読み取り機能の使用

通常、デバッグしたいプログラムは全体を -g オプションを使用して、コンパイルする必要があります。プログラムのコンパイル方法によって、各プログラムおよび共有ライブラリモジュールについて生成されるデバッグ情報は、各プログラムおよび共有ライブラリモジュールのオブジェクトコードファイル (.o ファイル)、またはプログラム実行可能ファイルのいずれか、あるいはこの両方に保存されます。

-g -c コンパイラオプションによってコンパイルを行うと、各モジュールのデバッグ情報は、その .o ファイルに保存されます。dbx は、各モジュールのデバッグ情報を必要に応じて、セッション中に自動的に読み取ります。この必要に応じた読み取り機能は、自動読み取り機能と呼ばれます。自動読み取り機能は、dbx のデフォルト機能です。

自動読み取り機能によって、大きなプログラムを dbx に読み込むときに時間を大幅に節約することができます。自動読み取り機能は、プログラム .o ファイルが、dbx に認識された位置に続けて存在することによって機能しています。dbx の認識後に .o ファイルを移動しないで下さい。


注 -

.o ファイル を .a ファイルに保存してから、アーカイブライブラリを使用してリンクすると、関連の .o ファイルを削除することができますが、.a ファイルは削除できません。


デフォルトにより、dbx はプログラムのコンパイル時にそれらのファイルがあったディレクトリからファイルを検索し、リンク元の位置から .o ファイルを検索します。 ファイルがそこにない場合は、pathmap コマンドを使用して、検索パスを設定してください。

オブジェクトファイルが作成されない場合、デバッグ情報は、実行可能ファイルに保存されます。つまり、.o ファイルを作成しないコンパイルの場合、コンパイラはすべてのデバッグ情報を実行可能ファイルに保存します。保存されたデバッグ情報は、-xs オプションでコンパイルされたアプリケーションと同じ方法で読み取られます。「.o ファイルが存在しない場合のデバッグ」を参照してください。

.o ファイルが存在しない場合のデバッグ

-g -c オプションでコンパイルされたプログラムは、各モジュールのデバッグ情報を、そのモジュールの .o ファイルに保存します。自動読み取り機能を使用するには、プログラム .o ファイルと共有ライブラリの .o ファイルが続けて存在している必要があります。

デバッグしたいモジュールのプログラムの .o ファイルまたは共有ライブラリの .o ファイルの維持が不可能な場合は、コンパイラの -xs オプションを使用して ( -g オプションの後に付けます) プログラムをコンパイルします。-xs でコンパイルしたモジュールと、このオプションを使わずにコンパイルしたモジュールが混在してもかまいません。-xs オプションは、コンパイラのリンカーに、すべてのデバッグ情報を実行可能プログラムに配置するよう命令するオプションです。したがって、これらのモジュールをデバッグするのに、.o ファイルの存在は必要ありません。

dbx 4.0 では、-xs オプションでコンパイルされたモジュールのデバッグ情報は、dbx の起動時に読み込まれます。そのため、-xs でコンパイルされた大きなプログラムでは、dbx の起動に時間がかかることがあります。

dbx 5.0 では、-xs でコンパイルされたモジュールのデバッグ情報は、.o ファイルに保存されたデバッグ情報と同様に遅延して読み込まれます。しかし、dbx に、これらの情報を起動時に読み込むよう命令することができます。dbx の環境変数 delay_xs を使用すれば、-xs でコンパイルされたモジュールのデバッグ情報の読み込み遅延機能をオフにすることができます。この環境変数を設定するには、.dbxrc ファイルに次の行を追加します。

dbxenv delay_xs off

モジュールのリスト

dbx module コマンドとそのオプションは、デバッグセッション中にプログラムモジュールを追跡するのに役立ちます。1 つまたはすべてのモジュールに関するデバッグ情報を読み取るには、module コマンドを使用してください。通常 dbx は、モジュールに関するデバッグ情報を、必要に応じて自動的かつ「緩慢に」読み取ります。

1 つのモジュール name に関するデバッグ情報を読み取るには、次のように入力します。


(dbx) module [-f] [-q] name

すべてのモジュールについてのデバッグ情報を読み取るには、次のように入力します。


(dbx) module [-f] [-q] -a

-f

ファイルが実行可能ファイルよりも新しい場合でも、デバッグ情報の読み取りを強制的に実行します。 

-q

詳細メッセージを表示しません。 

コマンド参照

modules

すでに dbx に読み取られたデバッグ情報を含むモジュールの名前をリスト表示するには、次のように入力します。


modules -read

すべてのプログラムモジュール名 (デバッグ情報付き、またはなし) をリスト表示するには、次のように入力します。


modules

デバッグ情報付きのすべてのプログラムモジュール名をリスト表示するには、次のように入力します。


modules -debug

現在のモジュール名を出力するには、次のように入力します。


module

whatis

非型識別子を出力するには、次のように入力します。


whatis [-n] [-r]

型識別子を出力するには、次のように入力します。


whatis -t [-r]

式を出力するには、次のように入力します。


whatis -e [-r]

list

数字が指定されていない場合に表示されるデフォルト行数は、dbxenv 変数の output_list_size によって決まります。場合によっては、行番号を $ (ドル記号) にすることができます。これは、ファイルの最後の行を示します。カンマは任意指定です。

特定の行番号を出力するには、次のように入力します。


list number

次の番号の行、または前の番号の行を出力するには、+ または - 記号を使用します。


list [ + | - ] number

ある番号から別の番号までの行をリスト表示するには、次のように入力します。


list number1 number2

filename で指定されるファイルの始まりをリスト表示するには、次のように入力します。


list filename

filename で指定されるファイルを number で指定される行番号からリスト表示するには、次のように入力します。


list filename:number

function のソースの始まりをリスト表示するには、次のように入力します。


list function

このコマンドは、現在のスコープを変更します。

ソース行とアセンブリコードを混合するには、次のように入力します。


list -i

number で指定された行を中心として表示するには、次のように入力します。


list -w number

このオプションは、+ または - 構文と組み合わせて使用することや、2 つの行番号が指定されている場合に使用することはできません。