未来のいつか/hyoshiokの日記

hyoshiokの日々思うことをあれやこれや

gdb豆知識

意外と知っているようでよく知らない自分が日々使う道具。そこで、gdbについて復習がてらいろいろ調べることにする。

gdbemacsから使う

gdbコマンドラインから素で使うのはいかがなものかなと思う。やっぱemacsと固く結合されているわけだからemacsから使うのが正しい姿であろう。

「え〜、だってvi使いだし〜」とか「秀丸からは使えないんすかね」とか言うやつがいるが、秀丸ってなんだよ、とりあえづubuntuでも入れて、emacsいれて、gdb使いなさいとか指導したくなる。いかんいかん、説教くさくなってはいかんいかん。

先日もある会議でデバッガの話が話題になったのだが、「TCPなんちゃらのストール問題のデバッグ方法なんですけどね」、みたいな話題で、「それってカーネルの話?」とわたしが聞くと、「いや、ユーザランドっす」と若いハッカー、「じゃ、gdbでほげほげでいけそーね」、「そーっすね」、「emacsから使うの王道だよね」、「えーーー、わたし使ったことないっすよ」、「えーーー、emacsでしょう」、「何がいいんすか?」、「上にgdbのコマンドの窓、下に対応するソース、ほら便利でしょう」、「ふーん」、「今まで誰も教えてくれなかったんかい?」、「はい」

みたいなラブリーな会話がくりひろげられた。

技術の伝承というか、当り前のテクニックすら伝承されていない。いいのか。大丈夫か。

昔はemacsみたいに資源を食うものは重くて使えないとか、そもそもemacsなんてインストールしていないよとか、いろいろあったわけだけど、さすがに昨今そんなことはないと思う。組み込み機器なので、そもそもgdbがないとかゆー環境もあるかと思うが、そーゆー環境でも、リモートでgdbを起動するという定番の使い方がされているわけだし、よっぽど特殊な環境でないかぎり、gdb+emacsでいいかと思う。Windowsでの使い方はここではよくわからないので触れない。

emacsからのgdbの起動はM-x gdb でOKである。

info registersでレジスタの値がわかる

(gdb) info registers
eax            0x0	0
ecx            0xb7ed7cd8	-1209172776
edx            0x0	0
ebx            0xb7ed6ff4	-1209176076
esp            0xbf963570	0xbf963570
ebp            0xbf9635b8	0xbf9635b8
esi            0xbf9635a4	-1080674908
edi            0xbf963654	-1080674732
eip            0x8049781	0x8049781 <main+113>
eflags         0x200392	[ AF SF TF IF ID ]
cs             0x73	115
ss             0x7b	123
ds             0x7b	123
es             0x7b	123
fs             0x0	0
gs             0x33	51

レジスタ名に$をつければ内容をprint(pと略称)できる

(gdb) p $ecx
$11 = -1209172776
(gdb) p/x $ecx
$12 = 0xb7ed7cd8

プログラムポインタ(pc)は$pcでもいい

(gdb) p $eip
$13 = (void (*)()) 0x8049781 <main+113>
(gdb) p $pc
$14 = (void (*)()) 0x8049781 <main+113>
(gdb) x/i $pc
0x8049781 <main+113>:	mov    -0x28(%ebp),%edx

xはメモリの中身を表示するコマンドだ。/iでその中身を命令として解釈して表示させている。Intel x86アークテクチャの場合、PCの事をeip (instruction pointer)と言うので、$pcも$eipも同じ値をさす。

printコマンドのフォーマット

printコマンドにかぎらないのだけど出力のフォーマットを変えたいときがある。あるときは10進数で表示したり、あるときは2進数、あるときは文字として表示したいなどという場合がある。

`x' 16進数で表示
`d' 10進数で表示
`u' 符号なしの10進数で表示
`o' 8進数で表示
`t' 2進数で表示。`t' は "two" からくる。
`a' アドレス
`c' 文字(ASCII)として表示
`f' 浮動小数点
`s' 文字列として表示

xコマンドのフォーマット

メモリの中身を表示するにはxコマンド(eXaminingからきている)を使う。上記のフォーマット以外にi(機械命令として表示)が利用できる。

x/NFU ADDR
x ADDR
x

という形式があって、ADDRというのは表示したいアドレスだとする。

ここでNは何回くりかえすか、Fは先に示した表示のフォーマット(`x', `d', `u', `o', `t', `a', `c', `f', `s', `i')、Uは下記の単位である

    `b' バイト
    `h' ハーフバイト(2バイト)
    `w' ワード(4バイト) デフォルト
    `g' ジャイアントバイト(8バイト)

(gdb) p argv
$28 = (char **) 0xbf963654
(gdb) p *argv
$29 = 0xbf96564d "/home/hyoshiok/work/coreutils-6.10/build-tree/coreutils-6.10/src/nl"
(gdb) x/s 0xbf96564d
0xbf96564d:	 "/home/hyoshiok/work/coreutils-6.10/build-tree/coreutils-6.10/src/nl"

続く。