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 <stdlib.h>
#include <stdio.h>

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 <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>

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