gdb hacks - gdb とターゲットプロセスとの通信を観察する
gdb hacks 第 2 回。今回は以下のトピックを扱います。
- gdb が関数の呼び出しでターゲットプロセス中に作成するデータ構造
- gdb とターゲットプロセスとの通信を観察する方法
サンプルデバッグセッションのログを gdb_target_debug.txt に用意していますので参照してください。実験環境は例によって i386 の Debian GNU/Linux (sid) です。
gdb とターゲットプロセスとのやりとりは、以下のように 3 つほどデバッグスイッチを有効にすると観察することができます (infrun デバッグスイッチは gdb 6.4 以降から使えます)。
119 (gdb) set debug target 1 120 (gdb) set debug infrun 1 121 (gdb) set debug lin-lwp 1 122 (gdb) p chdir("/etc")
こうして chdir("/etc") を呼び出すと大量のデバッグメッセージが出力されます。順番に見ていきましょう。
123 child:target_xfer_partial (2, (null), 0x0, 0xbfd13bf0, 0xbf9decb4, 4) = 4, bytes = 05 00 00 00 124 child:target_xfer_partial (2, (null), 0x0, 0xbfd13bf0, 0xbf9decb0, 4) = 4, bytes = e0 8b 04 08 125 infrun: proceed (addr=0xb7eee850, signal=0, step=0) 126 child:target_xfer_partial (2, (null), 0x837a070, 0x0, 0x8048be0, 1) = 1, bytes = 31 127 child:target_xfer_partial (2, (null), 0x0, 0xbfd13b50, 0x8048be0, 1) = 1, bytes = cc 128 infrun: resume (step=0, signal=0) 129 infrun: wait_for_inferior 130 CW: waitpid 4183 received 未知のシグナル(0) (terminated) 131 CW: waitpid 4179 received トレース/ブレイクポイント トラップ (stopped) 132 infrun: infwait_normal_state 133 infrun: TARGET_WAITKIND_STOPPED 134 infrun: stop_pc = 0x8048be0 135 infrun: BPSTATE_WHAT_STOP_SILENT 136 infrun: stop_stepping 137 child:target_xfer_partial (2, (null), 0x0, 0xbfd13b40, 0x8048be0, 1) = 1, bytes = 31
それぞれの意味は gdb のソースコードを grep して調べてほしいのですが、おおざっぱに説明するとだいたいこんな処理をしています。
123 0xbf9decb4 のワードに 0x00000005 を書く (スタックに引数をプッシュ) 124 0xbf9decb0 のワードに 0x08048be0 を書く (スタックに戻りアドレスをプッシュ) 126 0x08048be0 のバイトを保存 (= 0x31) 127 0x08048be0 のバイトに 0xcc (INT3) を書く (ブレークポイントの設定) 128 ターゲットプロセス実行開始 (0xb7eee850 番地から) 131 ブレークポイントを踏んだ 137 0x08048be0 のバイトを復元
謎なアドレスがいくつかでてきました。
- 0xbf9decb0 0xbf9decb4 はターゲットプロセスのスタック領域です (info registers で esp を見る)
- 0x08048be0 は .text セクションのスタートアドレスです (info target で調べられます)
- 0xb7eee850 は malloc() 関数のエントリポイントです (info symbol 0xb7eee850 で調べられます)
これはつまり gdb がターゲットプロセスに malloc(5) という関数呼び出しをさせていることを示します。関数からの戻りアドレスは .text 先頭の 0x08048be0 に設定され、ここに設置されたブレークポイントを踏んで gdb に制御が戻るという寸法です。
この直後に malloc() で確保した領域を 1 バイトづつ埋めにかかります。これは 0 終端文字列で "/etc" と書いていることは明白でしょう。
138 child:target_xfer_partial (2, (null), 0x0, 0xbfd13da0, 0x804ec80, 1) = 1, bytes = 2f 139 child:target_xfer_partial (2, (null), 0x0, 0xbfd13da0, 0x804ec81, 1) = 1, bytes = 65 140 child:target_xfer_partial (2, (null), 0x0, 0xbfd13da0, 0x804ec82, 1) = 1, bytes = 74 141 child:target_xfer_partial (2, (null), 0x0, 0xbfd13da0, 0x804ec83, 1) = 1, bytes = 63 142 child:target_xfer_partial (2, (null), 0x0, 0xbfd13da0, 0x804ec84, 1) = 1, bytes = 00
こうして初期化したメモリ領域を使って、同様に chdir("/etc") の呼出しを実行します。
143 child:target_xfer_partial (2, (null), 0x0, 0xbfd13fa0, 0xbf9decb4, 4) = 4, bytes = 80 ec 04 08 144 child:target_xfer_partial (2, (null), 0x0, 0xbfd13fa0, 0xbf9decb0, 4) = 4, bytes = e0 8b 04 08 145 infrun: proceed (addr=0xb7f47f10, signal=0, step=0) 146 child:target_xfer_partial (2, (null), 0x834bed8, 0x0, 0x8048be0, 1) = 1, bytes = 31 147 child:target_xfer_partial (2, (null), 0x0, 0xbfd13f00, 0x8048be0, 1) = 1, bytes = cc 148 infrun: resume (step=0, signal=0) 149 infrun: wait_for_inferior 150 CW: waitpid 4179 received トレース/ブレイクポイント トラップ (stopped) 151 infrun: infwait_normal_state 152 infrun: TARGET_WAITKIND_STOPPED 153 infrun: stop_pc = 0x8048be0 154 infrun: BPSTATE_WHAT_STOP_SILENT 155 infrun: stop_stepping 156 child:target_xfer_partial (2, (null), 0x0, 0xbfd13ef0, 0x8048be0, 1) = 1, bytes = 31 157 $1 = 0
これで終了です。戻り値 0 を報告して、gdb のプロンプトに戻ってきました。
ここで gdb が重大なことを忘れていることに気づいたでしょうか。そう、malloc() で確保したメモリを free() していません。遊び終わったらゴミはきちんと片付けておきましょう (もっとも通常はそのアドレスを知る術はないのですが…)。
162 (gdb) p free(0x804ec80)
このように gdb は式の評価中に文字列が出てくるとターゲットプロセス中で malloc() を呼び出してそのための領域を作ろうとします。つまり gdb が malloc() を見つけられないようなプログラム (static link して strip したバイナリなど) では、この機能は使えません。また malloc() で確保したメモリ領域は確保しっぱなしで開放されないので、デバッグ目的以外で、ターゲットプロセスの関数呼び出しはやめたほうがよさそうです。
今回は gdb のデバッグオプションをとりあげ、どのようにターゲットプロセスをいじっているのか確認する方法を説明しました。このデバッグ機能は新たなデバッグターゲットや、リモートデバッグのための gdb stub を作成する際に大変役に立ちます。
つづく。
カテゴリ
gdb hacksトラックバック(0)
このブログ記事を参照しているブログ一覧: gdb hacks - gdb とターゲットプロセスとの通信を観察する
このブログ記事に対するトラックバックURL: http://www.keshi.org/mt/mt-tb.cgi/32
コメントする