gdbの使い方 === # 変数の使用 ``` > set $x = malloc(10) > call snprintf($x, 10, "hoge\n") > p (char*) $x $4 = 0x28201030 "hoge\n" ``` # gdb内で文字列バッファを動的に扱う(基礎) ## モチベーション gdbを使っていると、gdb内でコードをテストしたいことがある。 その際、char*に結果を返すコマンドを実行したいケースがある。 この場合、gdb実施時に動的なメモリ確保と関数へのポインタ指示が必要になる。 どのようにやればよいのか?その手法について迫る。 ### やり方 以下のテストコードを使う ``` $ cat a.c // gcc -Wall -O0 -g a.c #include #include void abc(char *dst) { snprintf(dst, 16, "hoge\n"); } main() { char str[16]; char str2[16]; abc(str); asm("int $3"); printf("%s", str); } ``` # buildoutcfg コンパイルしてgdbします。 str, str2という2つの変数を定義し、 abcは引数に与えた変数を"hoge"とします。 int $3はBreakPointの割り込みを発生です。 ``` $ gcc -Wall -O0 -g a.c $ gdb ./a.out (gdb) r Starting program: /usr/home/kanai/tmp/zzz/a.out Program received signal SIGTRAP, Trace/breakpoint trap. main () at a.c:16 16 printf("%s", str); ``` breakした後、strのみabc()が適応されています。 想定通りです。 ``` (gdb) p str $1 = "hoge\n..." (gdb) p str2 $2 = "..." ``` では、str2にabc()を適応します。 ``` (gdb) p &str2 $6 = (char (*)[16]) 0xbfbfe5d4 (gdb) call abc(0xbfbfe5d4) $7 = void (gdb) p str2 $8 = "hoge\n..." ``` ここまでは問題ありませんね。 では、str2のような自由に使える変数がない場合は? mallocを使います。 ``` (gdb) call malloc(16) $3 = 673189936 (gdb) call abc(673189936) $4 = void (gdb) p (char (*)) 673189936 $5 = 0x28201030 "hoge\n" ``` mallocの結果673189936(10進数)=0x28201030(16進数)に 16バイトの空間をreserveします。 その空間にabcを適応し、無事に関数を実行できました。 以下は、同じことをしていますが、アドレスの表示を見やすくしています。 ``` (gdb) call/x malloc(16) $15 = 0x28201030 (gdb) call abc(0x28201030) $16 = void (gdb) p (char *)0x28201030 $17 = 0x28201030 "hoge\n" ``` 実践的なブレーク時のコマンド実行 ``` // gcc -Wall -g -O0 b.c #include #include #include #include #include #include void abc(struct sockaddr_in *sin) { char str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)); printf("entry: %s\n",str); } int main() { struct sockaddr_in servaddr[10]; int i; inet_pton(AF_INET, "192.168.0.3", &servaddr[0].sin_addr); inet_pton(AF_INET, "192.168.0.1", &servaddr[1].sin_addr); inet_pton(AF_INET, "192.168.1.3", &servaddr[2].sin_addr); inet_pton(AF_INET, "192.168.0.4", &servaddr[3].sin_addr); inet_pton(AF_INET, "192.168.10.3", &servaddr[4].sin_addr); inet_pton(AF_INET, "192.168.20.3", &servaddr[5].sin_addr); inet_pton(AF_INET, "192.168.30.3", &servaddr[6].sin_addr); inet_pton(AF_INET, "192.168.50.3", &servaddr[7].sin_addr); inet_pton(AF_INET, "192.168.60.3", &servaddr[8].sin_addr); inet_pton(AF_INET, "192.168.70.3", &servaddr[9].sin_addr); for (i = 0; i < 10; i++) { abc(&servaddr[i]); } return(0); } ``` コマンドセットは以下の通り ``` break abc commands 1 silent set $x = malloc(256) call inet_ntop(2, &sin->sin_addr, $x, 256) p (char *) $x call free($x) end ``` 尚、 ``` call inet_ntop(2, &sin->sin_addr, $x, sizeof($x)) ``` だとなぜかうごかない 実行例。 ``` (gdb) r Starting program: /usr/home/kanai/tmp/zzz/a.out $1 = 673190144 $2 = 0x28201100 "192.168.0.3" $3 = 672757056 (gdb) (gdb) (gdb) c Continuing. entry: 192.168.0.3 $4 = 673194240 $5 = 0x28202100 "192.168.0.1" $6 = 672757056 (gdb) c Continuing. entry: 192.168.0.1 $7 = 673194240 $8 = 0x28202100 "192.168.1.3" $9 = 672757056 (gdb) c Continuing. entry: 192.168.1.3 $10 = 673194240 $11 = 0x28202100 "192.168.0.4" $12 = 672757056 ```