Windowsネタが続いているので、お口直し(はぁと)
ガラっと変わってUNIXでAIXでCUIな世界のお話なんぞを(笑)
TURBO-Cデバッガと並んで、私が特に愛している?ラインデバッガがこれ。Windowsな世界の人には無縁かもしれませんが、UNIX系のCUIアプリを作るにあたってはこれを使える使えないじゃ大違いだったりします。UNIXでCUIな方々、ぜひぜひ使いこなしてやってくださいまし。Cはもちろん、FORTRANでも使えるとかなんとか。私はもっぱらC(純正、プリコンパイル版の両方)だったので、それで使ってました。
まず、プログラムは-gオプションをつけてコンパイル、必ずデバッガシンボル付きバイナリファイルで作成しておきます。DBXはこれとソースファイルを読み込んでラインデバッグしてくれるのでそれさえ忘れなければ大丈夫です。externでリンクする先の関数についてもデバッグしたい場合には、同様にデバッガシンボル付きコンパイルをしておけば、DBXが自動的に読み込んでくれます。
DBXの始め方
$ dbx プログラム
これだけ。プログラムバイナリファイルとソースファイルが同じディレクトリにいる場合にはこのまま実行できます。dbxが起動すると、(DBX)というDBXコマンドプロンプトがでますので、ここからコマンドを打ち込んで始めます。
ソースファイルが別ディレクトリにある場合には
(DBX) use ソースファイルディレクトリ
とすると、プログラムファイル名.c のファイルを探し出してきてソースファイルとして位置づけます。プリコンパイルファイルの情報がcソースプログラムに組み込まれている場合には、さらにその先のプリコンパイルソースファイルを見に行くように出来ているので心配ご無用。
ブレークポイントの設定
まずはブレークポイントを発行しておきましょう。DBXではstop命令でブレークポイントを設定できます。atの後はライン番号、inの後には関数名です。とにもかくにも、慣れない内はお約束として、まず、
(DBX) stop in main
だけは発行しておきます。せっかくのラインデバッガなんですから、とりあえず、最初の命令文では止めましょうよ(おい)って事ですね。後は、プログラムソースを片手に、止めたいところにどんどんとブレークポイントを設定していきます。
(DBX) stop at 182 :182行目の命令を実行する直前で止まります。
(DBX) stop in Main :Main関数に入った直後で止まります。
止まった時の状況は、atは指定ラインの命令実行直前、inは開始直後1行目命令実行直前、まだ命令文は処理されていません。後述の変数の中身を見る場合には「処理前の状態である」ということを忘れないようにしてください。
プログラム実行
(DBX) r
(DBX) rerun
コマンドrの後ろに色々とつけることで引数にできます。
(DBX) r XXXX XXXX XXXX
stop in main の実行前にやってしまうと最後まで一気に行っちゃうので注意。
ステップ実行
(DBX) c :次のブレークポイントまで実行します。ブレークポイントが無ければ終了しちゃいます
(DBX) n :次の同ネストの命令文まで実行。つまり、関数を処理していた場合には関数に入らず、処理して戻ってきます。
(DBX) s :次の命令文まで実行。関数処理でさらにネストされる場合には、その関数の中へと入っていきます。
上記のうち、cとnは次に設定されたブレークポイントまで処理が止まりません。ブレークポイントが見つからなかった場合には処理が終了します。
変数の中身を見る
10 char ps[5];
20 char *pt;
30 int ip;
40 ip = 0;
50 pt = ps;
60 pt++;
70 *pt = sprintf("%d",ip);
80 pt++;
というソース(脳内ソースで適当です。コンパイルしてないし。)で、
(DBX)stop at 80
とすると、70ラインの命令を処理した後、80ラインの命令を処理する直前、でブレークします。ここで
(DBX) p ps :配列の中身全部。構造体の場合は名前つきで表示
{"","0","","",""}
(DBX) p *pt :ポインタの指し示すアドレスの中身
"0"
(DBX) p pt :ポインタの指し示すアドレス
0x057f
とpコマンドを使うと変数の中を見ることができます。ポインタ変数の場合、名前だけを指定するとアドレスを表示し、「*」をつけると変数の指しているアドレスの中身を見ることができます。配列の場合には名前を指定するだけで中身全てを列挙してくれます。これは構造体も同じです。
p 変数名:変数の中身(ポインタ型の場合にはアドレス)
p *変数名:ポインタ型変数が指しているアドレスに格納されている値
基本的にこの二つを覚えておけば大丈夫です。
変数を変更しよう
pの使い方が判ったら、変数の中身の変更も簡単です。assignコマンドを使うと、変数の中身を変更でき、その記述ルールはそれぞれのプログラム言語に依存します。
(DBX) assign *pt = "1" :ポインタ変数ptのアドレス先の中身を変更
(DBX) assign ps[3] = '5' :変数ps[3]の中身を変更
(DBX) assign pt = 0x00 :ポインタ変数ptのアドレス先をNULLポインタに変更
pで見ることの出来た記述方式に従って、assign 変数 = 値 とすると、中身が書き換わります。これによって、分岐によるケース分けや本来なら発生し得ないだろうNULLポインタの処理や例外処理を発行させる事も可能になります。
トレースを使いこなそう
DBXにはトレース機能があります。ブレークポイントでいちいち止めてpコマンドを叩いて中身を見ているのが面倒な場合には、トレース機能を使うことで簡単に検証ログを作る事ができます
(DBX) trace ps at 80 :80行目の処理直前での変数psを中身を表示
(DBX) trace *pt in Main :main関数の処理直前直後での変数ptを中身を表示
traceコマンドを設定したラインや関数を通っても、処理は止まる事はありません。ブレークポイントにする必要は無いけれど、処理前後での値の変化や、ロジックが処理されたことを確認する必要がある場合にはトレースコマンドが便利です。
プログラムリストを見たい時
「今どのあたりにいるんだろう」「ちょっとあそこで止めたいな」という時にさくっとリストが表示できると便利ですね。
(DBX) list
とすると、ブレークポイントを設定した場所から以降のソースファイルを表示してくれます。プリコンパイルソースの場合はプリコンパイル前のものになります。続けてListを打つとスクロールのイメージで続きを表示してくれます。
(DBX) list XXX
とすると、XXX行目からの表示。以降をListすればそこから先のプログラムソースを見ることができます。
ちょっとShellを使いたい時
(DBX) Shell
とするとDBXを常駐させたまま、Shellに戻ります。この場合のShell環境はDBXを起動したShell環境なので、環境変数などもそのまま使えます。SQL文を実行したけど、結果が正しいかとか、ファイルはちゃんと書き込めたか、とか、I/Oの結果を知りたいときなんかに有効。Shell側からは
$ exit
とするとDBXに戻れます。
他にも、条件分岐Traceや条件分岐BreakPointなど、色々な使い方があるのですけれど、基本はそれくらいでしょうか(^^;
使う機会があれば、こんなのあったなぁ的に思い出していただけると幸いです。