8. データの調査

 あなたのプログラムのデータを調査する一般的な方法は `print' コマンド (省略形 `p') を用いることです。このコマンドは (今はC言語といった) プログラムの中で通常記述されているような、様々な妥当な式を評価して 表示します。あなたが
print exp
と入力した場合、exp は通常の形式の式であり、exp の値は そのデータ型を付け加えて表示されます。

 データを評価する更に低レベルの方法は `x' コマンドを用いることです。 このコマンドは、指定されたアドレス上のデータを調査し、指定された フォーマットで表示します。


8.1 式

 GDB 上の多くの異なるコマンドは式を受け付け、そしてその値を計算します。 定数、変数、又はプログラミング言語で定義されている任意のオペレータを、 あなたは GDB の式として当たり前に使用することができます。不幸にも、 プリプロセッサの #define コマンドで定義されたシンボルは含まれ ません。

 キャストは、C言語だけでなく、全ての言語においてサポートしています。 というのも、ポインタが指す数をキャストすることは、メモリ内のその アドレス上の構造を調査するのに便利だからです。

 GDB は、プログラミング言語が許可している式に加えて、次の3種類の オペレータをサポートしています:

@
`@' はメモリを配列として取り扱うためのバイナリ・オペレータです。 詳しくは“8.3 仮想配列”を参照して下さい。

::
`::' は、ファイルや関数で定義されている変数の参照を許可します。 “8.2 プログラム上の変数”を参照して下さい。

{type} addr
メモリ内の addr に格納されているオブジェクトを型 type で 参照します。addr は、その値が整数かポインタになる任意の式です (しかし、キャストと同じように、丸括弧が通常のオペレータのまわりに必要 です)。この構成は、addr においてうわべ上設定されているデータの 種類が無頓着な場合に許可されます。


8.2 プログラム上の変数

 最も一般的な種類の式は、あなたのプログラムの変数名を使うことです。

 式内の変数は、選択されたフレーム上で解釈されます(“6.3 フレームの選択”をご覧下さい); これらは、そのフレームにおいて処理が実行されている時、プログラミング 言語のスコープのルールに従って可視のものか、又はグローバル (もしくは static) のどちらかでなければなりません。このことは、次のような関数の 場合、

foo (a)
     int a;
{
  bar (a);
  {
    int b = test ();
    bar (b);
  }
}
変数 a はプログラムが関数 foo を実行している時は いつでも利用可能ですが、変数 bb が宣言されている ブロックの中をプログラムが実行している時にしか見えません。

 特例として、スコープが単一ファイルに限定されていて、カレントな実行 ポイントがそのファイルにない場合でさえ、変数や関数を参照することが できるようにすることが可能です。しかし、このことは、同一名称の変数や 関数を (もし、それらが異なったソースファイル上に存在するとして) 一つ 以上参照できてしまうことになります。このようなケースでは、どちらが 参照されるのかは定義されていません。もし、あなたが望むなら、これらの うちのどれか一つを、コロン-コロンという構造を用いて指定することが できます。

block::variable
block は、あなたが見たい変数名を含むソースファイルの名称です。


8.3 仮想配列

 メモリ上の同一の型のいくつかの連続するオブジェクトを表示することは、 時には便利なことがあります; しかし、配列や動的な配列の断片は、プログラムの内に存在するポインタに よってのみしかサイスが決定できません。

 これは、バイナリ・オペレータ `@' による仮想配列という構造に よって可能になります。`@' の左側のオペランドは配列にしたい最初の 要素で、単一のオブジェクトです。右側のオペランドは配列の長さです。 結果は、全ての要素が左側の引数の型になるような配列値です。最初の要素は、 正に左側の引数であり; 2番目の要素は最初の要素と同様の型がメモリのバイト列として続いて接して いるとみなし、残りも同様です。例を示しましょう。もし、プログラムに

int *array = (int *) malloc (len * sizeof (int));
と書かれていた場合、あなたは array の内容を次のようにして表示する ことができます。
p *array@len
 `@' の左側のオペランドはメモリ上に存在しなければなりません。 `@' を用いた方法によって作られた配列値は、予約語によるその他の 配列と同じようにふるまい、式の中で使われた場合はポインタを拘束します。 (これは、式が表示済みの変数の履歴を経由する場合に起こりえます。)


8.4 フォーマットに関するオプション

 GDB は、配列と構造体をどのように表示したらいいのかをコントロールするた めの、いくつかの方法を供給しています。
info format
カレントのフォーマットオプションの設定について表示します。

set array-max number-of-elements
もし、GDB が非常に大きな配列を表示するような場合、`set array-max' に 設定されている要素数だけ表示した後に、表示を停止します。この制限は、 文字列を表示する時などによく使われます。

set prettyprint on
GDB に、構造体を1つのメンバが1行にインデントされたフォーマットで 表示するように指示します。例えば次のように:

$1 = {
  next = 0x0,
  flags = {
    sweet = 1,
    sour = 1
  },
  meat = 0x54 "Pork"
}
set prettyprint off
GDB に、構造体をコンパクトなフォーマットで表示するように指示します。 例えば次のように:
$1 = {next = 0x0, flags = {sweet = 1, sour = 1}, meat = 0x54 "Pork"}
これは、デフォルトのフォーマットです。

set unionprint on
GDB に対して、構造体の中に共用体 (union) が含まれている場合は、それを 表示するように指示します。これはデフォルトの設定です。

set unionprint off
GDB は、構造体に含まれる共用体を表示しなくなります。

例えば、次のような宣言が与えられていた場合、

typedef enum {Tree, Bug} Species;
typedef enum {Big_tree, Acorn, Seedling} Tree_forms;
typedef enum {Caterpiller, Cocoon, Butterfly} Bug_forms;

struct thing {
  Species it;
  union {
    Tree_forms tree;
    Bug_forms bug;
  } form;
};

struct thing foo = {Tree, {Acorn}};
`set unionprint on' 時の `p foo' に対する効果は次のような 出力であり、
$1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}}
`set unionprint off' 時の効果は次のような出力となります。
$1 = {it = Tree, form = {...}}


8.5 出力フォーマット

 GDB は、通常、データの型に応じて全ての値を表示します。しかし、ときどき、 こうして欲しくない場合があります。例えば、あなたが数字を16進数で表示 したい場合とか、ポインタを10進数で表示したい場合とか。又、メモリの 実アドレスにあるデータを、文字列や命令として見てみたい場合もある でしょう。これらは、出力フォーマットを利用することで実現 できます。

 出力フォーマットの簡単な使い方は、既に計算済みの値をどのように 表示するかを指示するというものです。これは、`print' コマンドの 最初の引数を、スラッシュで始まってフォーマット文字で終わらせることに よって実現できます。フォーマット文字には、次のようなものがサポート されています:

‘x’
値のビット列を整数値とみなし、その整数値を16進数で表示します。
‘d’
整数値を符号付き10進数で表示します。
‘u’
整数値を符号なし10進数で表示します。
‘o’
整数値を8進数で表示します。
‘a’
16進数の絶対アドレス、又はそれに以下にあるアドレスに定義された シンボルの相対アドレスとして表示します。
‘c’
整数値とみなして、それを文字定数で表示します。
‘f’
ビット列を浮動小数点値とみなし、典型的な浮動小数点表記を使って表示 します。
 例えば、プログラムカウンタ (“8.9 レジスタ”をご覧下さい)を16進数で表示する場合は、 次のように入力します。
p/x $pc
スラッシュの前にはスペースが必要でないことを覚えておいて下さい; この理由は、GDB のコマンドにはスラッシュを含んだ名称が存在しない ということだからです。

 変数値の履歴にある最後に表示した値を異なったフォーマットで再表示したい 場合は、式なしの `print' コマンドにフォーマットを指定して下さい。 例えば、`p/x' は最後に表示した値を16進数で再表示します。


8.5.1 メモリの調査

 `x' というコマンド (由来は‘examine’) は、プログラムのデータ 型を参照せずにメモリを調べるときに使うことができます。あなたが調べたい メモリのフォーマットは、ある決まった方法で記述されます。許可されている フォーマットは、以前の章で述べてきたフォーマットのスーパーセットに なっています。

 `x' はスラッシュの後にフォーマットに関する記述、そしてその後に アドレスに関する記述を受け付けます。式には (もし通したとしても) ポインタ 値が使えないので; そこにはメモリのバイト列の整数値やアドレスが使われます。 式の詳細は、“8.1 式”を参照して下さい。 例えば、`x/4xw $sp' はスタックポインタ上のメモリを4ワードの 16進数で表示します。

 このケースにおける出力フォーマットでは、調査するメモリの大きさと、 そのユニットの内容をどのように表示するのかということを記述します。 これには、この後に説明する1つか2つの文字で指定します:

 次に示す文字は、まさに調査対象のユニットのサイズを記述します:

b
単一バイトで調査します。

h
半ワード (2バイト) で調査します。

w
ワード (4バイト) で調査します。

多くのアセンブラとCPU設計者は、祖先となる1970年代のマシンが実際に 2バイトのワードを利用していたという名残により、`ワード'をいまだ 16ビットのサイズとして定義しています。しかし、一般的に言うと、 `ワード'は、マシンが通常レジスタで操作したり記憶したりするサイズだと いうのが、語源です。GDB が動作する全てのマシンにおいて、このサイズは 32ビットです。

g
巨大ワード (8バイト) で調査します。
 次の文字は内容を表示する方法を記述するためのものです:
x
符号なし16進整数値で表示します。

d
符号付き10進整数値で表示します。

u
符号なし10進整数値で表示します。

o
符号なし8進整数値で表示します。

a
絶対アドレス、またはシンボルに定義された相対アドレスで表示します。

c
文字定数で表示します。

f
浮動小数点で表示します。これは、`w'`g' のサイズでのみ 有効です。

s
null-ターミネートされた文字列として表示します。指定されたユニットサイズは 無視され; かわりに null キャラクタまで達する多くの (null キャラクタを含んだ) バイト 列を持つことになります。

i
アセンブラ・シンタックスでの (もしくは、それに近い) マシン・ インストラクションを表示します。指定されたユニットサイズは無視され; 1つのインストラクションを構成するバイト数は、そのマシンで利用されている オペコードとアドレッシングモードの種類に依存します。
 表示方法やユニットサイズの指定がなかった場合、使用されるデフォルト値は 最後に使用されたのと同じものです。もし、あなたがスラッシュの後に何の 文字も使用したくないという場合は、スラッシュもまた省略できます。

 あなたは、また、調査対象アドレスも省略可能です。この場合、ユニットが 最後に調査されたアドレスが使用されます。これは、データをベースとして ユニットサイズが計算されるような、文字列とインストラクション・ フォーマットのためのものです: というのも、次の文字列やインストラクションは正しい位置から調査を 開始しなければならないからです。`print' コマンドは、時折 `x' コマンドのためのデフォルトアドレスを設定します; メモリ上に位置する値が表示された時、デフォルトで同一の 位置が設定されています。`info line' はまた `x' と同様に 指定された行のマシンコードの開始アドレスにデフォルトを設定し、 `info breakpoints' は、最後に表示されたブレークポイントの アドレスにデフォルトを設定します。

 RET により `x' コマンドがリピートされた時は全く同様の内容を リピートしません: 指定されたアドレスは (もしあれば) 無視され、リピートされたコマンドは 同一の場所のかわりに連続したメモリ位置を調査します。

 あなたは、更に、コマンドに対してスラッシュの後に (また、もしあれば フォーマット文字の前に) 繰り返し回数を書くことで、いくつかの連続的な メモリユニットを調査することができます。繰り返し回数は10進数の整数で なければなりません。これは、`x' コマンドがリピートされた時と 同様な効果を持ち、出力は行ごとのいくつかのユニットに対して、より コンパクトになります。例えば、

x/10i $pc
は、選択されているフレームにおいて次に実行されるインストラクションから 10個のインストラクションを表示します。この後、あなたは、次のように入力 することで、更に10個のインストラクションを表示できます。
x/10
これは、フォーマットとアドレスにおいてデフォルト値が使われるからです。

 `x' コマンドによって表示されるアドレスとその内容は、 あまりにも多すぎ、それらを記録するのが邪魔なので、変数履歴に代入 されません。そのかわりに、GDB は、簡易変数 $_$__ の 値を式で使うという別な手段を提供しています。

 `x' コマンドの後、最後に調査されたアドレスは、 式内の簡易変数 $_ によって参照可能となります。そのアドレスの 内容は、調査されたならば、簡易変数 $__ においても有効です。

 もし、`x' コマンドが繰り返されたならば、アドレスと内容は最後に 表示されたメモリユニットの形態として保存されます; これは、最後の行の出力においていくつかのユニットが表示された時の 最後のアドレス表示の内容とは異なります。

 `disassemble' という特別なコマンドは、与えられたメモリレンジを マシン・インストラクションとしてダンプします。デフォルトのメモリ レンジは、選択されているフレーム上のプログラムカウンタを取り囲む 関数の範囲です。このコマンドへ一つの引数を渡した場合、これは、 プログラムカウンタ値となります; この値を取り囲む関数がダンプされます。2つの引数を渡した場合は、 ダンプするアドレスの範囲を示します。(最初が包括的、2つ目が排他的。)


8.6 自動的な表示

 もし、あなたが式の値を (それらがどのように変わっていくのか調べるために) 頻繁に表示したいと思った場合、それを自動表示リストに加えておけば、 GDB はプログラムが停止した時に、その値を表示します。 リストに追加されるそれぞれの式は、付与される数字によって識別されます; リストからその式を削除したい場合は、数字を指定する必要があります。 自動的な表示とは次のようなものです:
2: foo = 38
3: bar[5] = (struct hack *) 0x3804
アイテム番号と式、そしてそれらのカレントな値を表示します。

 もし、式がローカル変数を参照している場合、それが設定された語意上の 文脈の範囲外では意味を成しません。このような式は、実行処理が語意上の 文脈の中にある時にのみ、表示されます。例えば、あなたが関数内で、 引数 name を表示する `display name' というコマンドを与えた 場合、この引数はプログラムがその関数内部で停止する時に表示されますが、 それ以外の場所に停止した時は (この引数がどこにも存在しないので) 表示 されません。

display exp
exp を、プログラムが停止した時に表示する式のリストに追加します。 “8.1 式”を参照して下さい。

display/fmt exp
サイズや回数ではない fmt を表示用のフォーマットとして指定し、 exp を自動表示リストに追加します。表示は fmt に従って アレンジされます。

display/fmt addr
`i'`s' や、ユニットサイズ、ユニット数を含む fmt において、addr の式をプログラムが停止した時に調査する メモリアドレスとして追加します。調査内容は、`x/fmt addr' と同様です。“8.5.1 メモリの調査
undisplay dnums...
delete display dnums...
表示する式のリスト上の dnums であらわされるアイテムを削除します。

disable display dnums...
dnums で表されるアイテムの表示を無効にします。表示が無効になった アイテムは自動的に表示されませんが、忘れ去られたわけではありません。 これは、後で有効にすることができます。

enable display dnums...
dnums で表されるアイテムの表示を有効にします。これは、あなたが 別なことを指定するまでは、再びその式を自動表示するようになります。

display
リスト上の式のカレント値を、プログラムが停止した時と同様に表示します。

info display
今までに自動表示するように設定されている式のリストを、それぞれアイテム 番号付きで表示しますが、その値は表示しません。この中には無効になった 式も含まれ、無効を表すマークが付きます。これには、また、 カレントでは有効でない automatic 変数を参照しているために、 通常表示されないような式も含みます。


8.7 変数値の履歴

 `print' コマンドによって表示される各々の値は、他の式から参照する ことができる GDB の変数履歴というセッションに保存されます。

 表示された値は、あなたがそれによって参照できるようにするために、 履歴番号が付与されます。 これらは、1ではじまる連続する整数値です。`print' は、指定 された値を表示する前に `$num = ' という形式で履歴番号を 表示します; この num が履歴番号です。

 以前の任意の値を参照する場合、その値の履歴番号を後に持つ `$' を 使います。`print' によって表示される出力は、あなたにこのことを 気付かせるようにデザインされています。単なる $ は履歴上の最も 最近の値を参照し、$$ は、その直前の値を参照します。

 例えば、ポインタの構造を表示した後で、その内容を再び見たくなったと仮定 しましょう。これは、次のように入力するだけで十分です。

p *$
 もし、構造体がチェインを持ち、`next' が次の構造体をポイントして いる場合、次の構造体の内容を表示させる時には、このようにします:
p *$.next
RET を何回も入力することでこのコマンドを繰り返すのは、 とても便利でしょう。

 履歴は値を記録しており、式を記録しているわけではないことに注意して 下さい。x の値が4であるとして、あなたが次のコマンドを入力したら:

print x
set x=5
変数履歴に記録されている値は、いかに変数 x の内容が変更されたと しても、`print' コマンドが表示した4のままです。
info values
変数履歴の最後の10個の値を、その番号と共に表示します。これは、 `p $$9' を10回繰り返したのと同様ですが、`info values' は、 履歴を変更しないという部分だけ異なります。

info values n
アイテム番号 n を中心とした10個の変数履歴を表示します。

info values +
最後に表示された値の後の10個の変数履歴を表示します。


8.8 簡易変数

 GDB は、GDB がその中に値をしまうことで、あなたが後から参照することが できるようにするための、簡易変数というものをサポートしています。 これらの変数は GDB 全体に存在し; これらはあなたのプログラムの一部ではなく、簡易変数への値の設定は、 あなたのプログラムの実行に対して何も影響を与えません。これを あなたは自由に使うことができます。

 簡易変数は、`$' ではじまる名称を持ちます。`$' ではじまる 任意の名称は、既に定義済みのレジスタ名 (“8.9 レジスタ”をご覧下さい) を除けば、 簡易変数として扱われます。

 あなたは、プログラムで変数値を設定する時のように、式による代入を 使うことで簡易変数に値を保存することができます。例えば:

set $foo = *object_ptr
object_ptr でポイントされるオブジェクトの 内容値を $foo に保存することができます。

 簡易変数を最初に使った場合、まずそれは生成されます; しかしその値は、あなたが新しい値を設定するまでは void 値です。 あなたは、いつでも、他の代入を行い、値を変更することができます。

 簡易変数には、決まった型がありません。あなたは、簡易変数に対して、 既に設定されている値とは異なった型であったとしても、任意の型の値を 設定することができます。簡易変数は、たとえカレント値がどんな型で あっても式になりえます。

info convenience
今までに利用された簡易変数のリストを表示します。 省略形は、`i con' です。
 簡易変数を利用する一つの方法に、インクリメント用のカウンタや 先に進むポインタとしての活用法があります。例えば:
set $i = 0
print bar[$i++]->contents
...RET を入力することで、このコマンドを繰り返す。
 ある簡易変数は GDB によって自動的に生成され、便利であろうと思われる値を 持っています。
$_
$_ という変数は `x' コマンドによって最後に調査した アドレスが自動的に設定されます(“8.5.1 メモリの調査”をご覧下さい)。 `x' で調査するためのデフォルトアドレスを供給する他のコマンドも また、$_ にそのアドレスを設定します; これらのコマンドには、`info line'`info breakpoint' も 含みます。

$__
$__ という変数は、`x' コマンドが最後に調査したアドレスで 見つかった値が自動的に設定されます。


8.9 レジスタ

 マシン上のレジスタの内容は、`$' で始まる、変数と同様の式で 参照することができます。レジスタの名称はマシンごとに異なりますので; `info registers' で、あなたのマシンにおいて使われているレジスタの 名称を調べて下さい。$pc$sp という名称は、 全てのマシンにおいてプログラムカウンタ及びスタックポインタとして使われ ます。また、$fp がカレントのスタックフレームの内容を持つ レジスタとして用いられ、$ps はプロセッサステータスの内容を保持 しているレジスタとして使われています。これらの標準レジスタ名は、あなた のマシンにおいて info registers コマンドを使ってみると、 異なった名称で表示されるかもしれません。例えば、SPARC では、 info registers はプロセッサステータス・レジスタとして $psr を表示しますが、これを $ps で参照することもできます。

 GDB は、レジスタ値がこの方法で調査された場合、普通のレジスタが持つ内容を 整数値とみなします。あるマシンはレジスタ値が浮動小数点値とみなされる ような; 浮動小数点値を記憶できる特別なレジスタを持っています。 しかし、(たとえ、あなたが print コマンドを使って、 `print/f $regname' のように浮動小数点値として表示しようと したとしても) 普通のレジスタの内容を浮動小数点値とみなす方法は ありません。

 あるレジスタは“raw”や“virtual”という独特のデータフォーマットを 持っています。これは、オペレーティング・システムによって保存された レジスタの内容が、あなたのプログラムから通常見える内容と同じでない データフォーマットのことです。例えば、68881浮動小数点演算コ・プロセッサの レジスタは、“拡張された”フォーマットで保存されますが、全ての C言語プログラムは、結果を“double”フォーマットで要求します。 このようなケースの場合、GDB は、通常、仮想 (virtual) フォーマット (あなたのプログラムが理解できるフォーマット) のみで動作しますが、 `info registers' コマンドは、両方のフォーマットのデータを表示します。

 レジスタ値は選択されているスタックフレームに対して相対的 です(“6.3 フレームの選択”をご覧下さい)。あなたが値を得る時、もし離れたところにある 全てのスタックフレームが破棄され、それらに保存されていたレジスタが 復活されたならば、レジスタは内容を持っています。全てのレジスタの 実際の内容を見る手段としては (`frame 0' などのように) 最深部の フレームを選択しなければなりません。

 あるレジスタは、関数値を返すことに使われるという理由のために、 決して保存されることはありません(それらの代表的な値はゼロか1です); これらのレジスタにとって、相対関係は無意味です。

info registers
全てのレジスタの名称と、相対的な値を表示します。

info registers regname
regname で示されるレジスタの相対的な値を表示します。 regname はあなたが使用しているマシンにおいて正当な任意の レジスタ名であり、最初に `$' がつきます。


8.9.1 例

 あなたは、次のように入力することで、プログラムカウンタを16進数で表示 できます。
p/x $pc
また、次に実行されるインストラクションを表示する場合は、次のように 入力します。
x/i $pc
また、スタックポインタに4を足す場合は次のようにします。
set $sp += 4
最後の例は、スタックがメモリの下方へと進むマシン (今日において一般的な マシン) において、スタックから1ワード削除する方法です。 これは、最深部のスタックフレームが選択されていることを仮定しています。 他のスタックフレームが選択されていた場合、$sp への値設定は 許可されません。


目次に戻る