gdb hacks - gdb を電卓の代わりに使う

| | コメント(0) | トラックバック(0)

gdb hacks 第 3 回。今回は以下のトピックを扱います。

  • gdb を電卓の代わりに使う
  • gdb が扱うシンボルの型情報

筆者は gdb を電卓代わりによく使っています。以下のように出力フォーマットを手軽に指定できること、C の表現式がそのまま使えること、前の計算結果を簡単に参照できることなど、他の電卓プログラムにはない魅力があります。bc や irb と比較しても gdb はよりプログラマ向きの電卓なのではないかと思います。

% gdb
(gdb) p 123+456+789
$1 = 1368
(gdb) p 123+0456+0x789
$2 = 2354
(gdb) p/o $2
$3 = 04462
(gdb) p/x $3
$4 = 0x932
(gdb) p/t $4
$5 = 100100110010
(gdb) p/x 'a'
$6 = 0x61
(gdb) p/c 0x41
$7 = 65 'A'
(gdb) p 123e4/567.8
$8 = 2166.2557238464251
(gdb) p "hoge"
evaluation of this expression requires the target program to be active

(わざとらしいですが)最後に文句を言われてしまいました。配列や文字列といったオブジェクトのメモリ領域を確保したり、関数を実行したりするには、ターゲットプロセスのコンテキストが必要になります。

ターゲットプロセスはデバッグできるプログラムであればなんでもいいので、以下のように main() だけを含む a.out を適当に作って使ってみます。

% echo "int main(){returnh 0;}" | gcc -xc -
% gdb a.out
(gdb) start
Breakpoint 1 at 0x804835a
Starting program: /home/yaegashi/a.out
0x0804835a in main ()
(gdb) p "hoge"
$1 = "hoge"
(gdb) ptype $1
type = char [5]
(gdb) p printf("%s%s\n", $1, $1)
hogehoge
$2 = 9
(gdb) p {(char*)"ls", (char*)"/", (char*)0}
$3 = {0x804a028 "ls", 0x804a038 "/", 0x0}
(gdb) p execvp("ls", $3)
app  boot  etc   initrd  media  opt   root  srv  tmp  var
bin  dev   home  lib     mnt    proc  sbin  sys  usr

Program exited normally.
The program being debugged stopped while in a function called from GDB.
When the function (execvp) is done executing, GDB will silently
stop (instead of continuing to evaluate the expression containing
the function call).
(gdb)

gdb 電卓コンテキスト用の a.out ができましたので、調子に乗って libm の数学関数を使うことを考えてみます。a.out に libm をリンクせずとも、環境変数 LD_PRELOAD を使って ld.so に libm.so を読み込ませてしまえば、gdb から libm の関数にアクセスすることができます。

% gdb a.out
(gdb) set environment LD_PRELOAD=/lib/libm.so.6
(gdb) start
Breakpoint 1 at 0x804835a
Starting program: /home/yaegashi/a.out
0x0804835a in main ()
(gdb) p sqrt(2.0)
$1 = 14624
(gdb) p/f $1
$2 = 2.04925887e-41

しかし、なんだか意図したものとは全然違う結果が返ってきました。

これは ptype を使って sqrt の型について調べてみれば原因がわかります。

(gdb) ptype sqrt
type = int ()

このように gdb は sqrt 関数を整数値 int を返す関数だと考えていることがわかります。本来なら sqrt は浮動小数点値を返すので戻り値は浮動小数点値スタックのトップ (st0) に置かれるはずなのですが、gdb は EAX レジスタの内容を戻り値として報告してしまっているのです。

これを是正するには gdb に sqrt の正しい型情報を教えなくてはなりません。Debian にはデバッグ情報を含む glibc を収めた libc6-dbg というパッケージがありますので、こちらの libm.so.6 を使ってみます。

% apt-get install libc6-dbg
% gdb a.out
(gdb) set environment LD_PRELOAD=/usr/lib/debug/libm.so.6
(gdb) start
Breakpoint 1 at 0x804835a
Starting program: /home/yaegashi/a.out
0x0804835a in main ()
(gdb) ptype sqrt
type = int ()
(gdb) ptype __sqrt
type = double (double)
(gdb) p __sqrt(2.0)
$1 = 1.4142135623730951

sqrt はあいかわらずだめでしたが、__sqrt というシンボルでは正しく型情報が設定されており、期待どおりの値が返ってきることがわかります。

これで gdb 電卓でも数学関数が使えるようになり少し実用度が増しましたが、__sqrt(2.0) などという表記はあまりスマートとはいえません。実際には gdb に望みの型情報を与えるもうすこしまともな方法があるような気がしているので、引き続き調査してみる予定です。

つづく。

カテゴリ

トラックバック(0)

このブログ記事を参照しているブログ一覧: gdb hacks - gdb を電卓の代わりに使う

このブログ記事に対するトラックバックURL: http://www.keshi.org/mt/mt-tb.cgi/33

コメントする

このブログ記事について

このページは、yaegashiが2006年3月 1日 03:41に書いたブログ記事です。

ひとつ前のブログ記事は「gdb hacks - gdb とターゲットプロセスとの通信を観察する」です。

次のブログ記事は「gdb hacks - gdbcalc スクリプト」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

Powered by Movable Type 4.0