gdb豆知識
意外と知っているようでよく知らない自分が日々使う道具。そこで、gdbについて復習がてらいろいろ調べることにする。
gdbはemacsから使う
gdbをコマンドラインから素で使うのはいかがなものかなと思う。やっぱemacsと固く結合されているわけだからemacsから使うのが正しい姿であろう。
「え〜、だってvi使いだし〜」とか「秀丸からは使えないんすかね」とか言うやつがいるが、秀丸ってなんだよ、とりあえづubuntuでも入れて、emacsいれて、gdb使いなさいとか指導したくなる。いかんいかん、説教くさくなってはいかんいかん。
先日もある会議でデバッガの話が話題になったのだが、「TCPなんちゃらのストール問題のデバッグ方法なんですけどね」、みたいな話題で、「それってカーネルの話?」とわたしが聞くと、「いや、ユーザランドっす」と若いハッカー、「じゃ、gdbでほげほげでいけそーね」、「そーっすね」、「emacsから使うの王道だよね」、「えーーー、わたし使ったことないっすよ」、「えーーー、emacsでしょう」、「何がいいんすか?」、「上にgdbのコマンドの窓、下に対応するソース、ほら便利でしょう」、「ふーん」、「今まで誰も教えてくれなかったんかい?」、「はい」
みたいなラブリーな会話がくりひろげられた。
技術の伝承というか、当り前のテクニックすら伝承されていない。いいのか。大丈夫か。
昔はemacsみたいに資源を食うものは重くて使えないとか、そもそもemacsなんてインストールしていないよとか、いろいろあったわけだけど、さすがに昨今そんなことはないと思う。組み込み機器なので、そもそもgdbがないとかゆー環境もあるかと思うが、そーゆー環境でも、リモートでgdbを起動するという定番の使い方がされているわけだし、よっぽど特殊な環境でないかぎり、gdb+emacsでいいかと思う。Windowsでの使い方はここではよくわからないので触れない。
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"
続く。