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