LoginSignup
5
3

More than 5 years have passed since last update.

gdbのDynamic Printfを使う

Last updated at Posted at 2017-05-06

はじめに

gdbのDynamic pinrtf機能を使うことで動的にprintfを挿入できます。
breakすることなくプログラムの変数 / 実行パス を確認できます。

使い方

QEMU / gdb で Linux kernel の動きを確認するを例に説明します。

consoleAでQEMUを起動します。

consoleA
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します。

consoleB
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

consoleB
(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の出力が表示されます。

consoleB
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

consoleB
(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と類似のことができます。

consoleB
(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との違いについてはこちらを参照ください。

references

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3