はじめに
gdbのDynamic pinrtf機能を使うことで動的にprintfを挿入できます。
breakすることなくプログラムの変数 / 実行パス を確認できます。
使い方
QEMU / gdb で Linux kernel の動きを確認するを例に説明します。
consoleAでQEMUを起動します。
TOP_LINUX=~/linux-3.13.0
TOP_BUSYBOX=~/busybox-1.26.2
qemu-system-x86_64 -s -nographic \
-kernel $TOP_LINUX/arch/x86/boot/bzImage \
-initrd $TOP_BUSYBOX/rootfs.img \
-append "root=/dev/ram rdinit=/sbin/init console=ttyS0"
別のconsoleBでgdbを起動してtarget remoteします。
gdb vmlinux
GNU gdb (Ubuntu 7.7-0ubuntu3) 7.7
(snip)
Reading symbols from vmlinux...done.
(gdb) target remote :1234
プログラムを実行するとkernel の do_execveがcallされます。
do_execveの引数 filenameを表示してみます。
dprintf do_execve, "do_execve fname=%s\n", filename
(gdb) l do_execve
1577 }
1578
1579 int do_execve(const char *filename,
1580 const char __user *const __user *__argv,
1581 const char __user *const __user *__envp)
1582 {
1583 struct user_arg_ptr argv = { .ptr.native = __argv };
1584 struct user_arg_ptr envp = { .ptr.native = __envp };
1585 return do_execve_common(filename, argv, envp);
1586 }
(gdb) dprintf do_execve, "do_execve fname=%s\n", filename
(gdb) c
consoleAで ls / find / catのコマンドを入力するとconsoleBにdprintfの出力が表示されます。
do_execve fname=/bin/ls
do_execve fname=/usr/bin/find
do_execve fname=/bin/cat
address指定
dprintfで表示する場所をaddress指定できます。
do_execveのアドレスを調べます。アドレス指定でdprintfを設定します。
dprintf *0xffffffff8108bc62, "do_execve rax=%llx\n", $rax
(gdb) disas do_execve
Dump of assembler code for function do_execve:
0xffffffff8108bc60 <+0>: push %r15
0xffffffff8108bc62 <+2>: mov 0xffffffff8141d080,%rax
0xffffffff8108bc6a <+10>: push %r14
0xffffffff8108bc6c <+12>: mov %rsi,%r14
(snip)
(gdb) dprintf *0xffffffff8108bc62, "do_execve rax=%llx\n", $rax
(gdb) c
Continuing.
do_execve rax=ffff88000005800
consoleAでコマンドを入力するとdprintfの結果が表示されます。
do_execve rax=ffff88000005800
削除
breakの削除と同じです。
(gdb) i b
Num Type Disp Enb Address What
8 dprintf keep y 0xffffffff8108bc62 in do_execve
at /home/user/linux-3.13.0/arch/x86/include/asm/current.h:14
breakpoint already hit 2 times
printf "do_execve rax=%llx\n", $rax
(gdb) d 8
(gdb) i b
No breakpoints or watchpoints.
(gdb)
Breakpoint Command Lists
break pointを通過したときに実行したいCommand Listsを登録できます。
Breakpoint Command Listsといいます。この機能を使うとdprintfと類似のことができます。
(gdb) b do_execve
Breakpoint 18 at 0xffffffff8108bc60: file fs/exec.c, line 1582.
(gdb) commands 18
Type commands for breakpoint(s) 18, one per line.
End with a line saying just "end".
>silent
>p filename
>c
>end
(gdb) c
Continuing.
$7 = 0xffff880000058020 "/bin/ls"
$8 = 0xffff880000058020 "/bin/ls"
$9 = 0xffff880000058020 "/bin/cat"
(gdb) i b
Num Type Disp Enb Address What
18 breakpoint keep y 0xffffffff8108bc60 in do_execve
at fs/exec.c:1582
breakpoint already hit 4 times
silent
p filename
c
(gdb)
dprintfとの違いについてはこちらを参照ください。