2013年8月7日 星期三

使用 GDB 追縱執行中程式裡面的變數值

首先是要安裝 debug symbols 的套件來使用。

Debian 可以參考 HowToGetABacktrace - Debian Wiki
Ubuntu 可以參考 DebuggingProgramCrash - Ubuntu Wiki

例如目標是 Ubuntu 12.04 中的 Xorg 裡面的 positionSprite() 函式在執行時傳入的變數值,所以先用

$ ps aux | grep X
root      1044  0.4  1.0 127440 21524 tty7     Ss+  18:44   0:06 /usr/bin/X :0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch -background none
u         2633  0.0  0.0  13616   928 pts/2    S+   19:11   0:00 grep --color=auto X
來找出 Xorg 的 PID

然後執行以下指令:

$ sudo gdb /usr/bin/Xorg 1044                                                                                                                                                                         
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /usr/bin/Xorg...Reading symbols from /usr/lib/debug/usr/bin/Xorg...done.
done.
Attaching to program: /usr/bin/Xorg, process 1044
Reading symbols from /lib/x86_64-linux-gnu/libudev.so.0...(no debugging symbols found)...done.
Loaded symbols for /lib/x86_64-linux-gnu/libudev.so.0
... [省略]
(gdb) set height 0
(gdb) break positionSprite
Breakpoint 1 at 0x7fedc71d1140: file ../../dix/getevents.c, line 940.
(gdb) c
Continuing.

Breakpoint 1, positionSprite (dev=0x7fedc94105d0, mode=0, mask=0x7fff3c6e6780, devx=0x7fff3c6e6770, devy=0x7fff3c6e6778, screenx=0x7fff3c6e6760, screeny=0x7fff3c6e6768) at ../../dix/getevents.c:940
940     ../../dix/getevents.c: 沒有此一檔案或目錄.
(gdb) commands
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>print *devx
>print *devy
>print *screenx
>print *screeny
>continue
>end
(gdb) c
Continuing.

接下來移動滑鼠就可以看到以下的訊息。

Breakpoint 1, positionSprite (dev=0x7fedc94105d0, mode=0, mask=0x7fff3c6e6780, devx=0x7fff3c6e6770, devy=0x7fff3c6e6778, screenx=0x7fff3c6e6760, screeny=0x7fff3c6e6768) at ../../dix/getevents.c:940
940     in ../../dix/getevents.c
$45 = 1023.4510981145139
$46 = 757.60130195816362
$47 = 1366.6023460649326
$48 = 758.58904811456273

Breakpoint 1, positionSprite (dev=0x7fedc94105d0, mode=0, mask=0x7fff3c6e6780, devx=0x7fff3c6e6770, devy=0x7fff3c6e6778, screenx=0x7fff3c6e6760, screeny=0x7fff3c6e6768) at ../../dix/getevents.c:940
940     in ../../dix/getevents.c
$49 = 1022.651098102593
$50 = 757.60130195816362
$51 = 1365.5341153549775
$52 = 758.58904811456273

可以將設定好的 breakpoints 的動作儲存成一個腳本檔

(gdb) save breakpoints break.cmd
Saved to file 'break.cmd'.

腳本的內容是:

set height 0
break positionSprite
  commands
    print *devx
    print *devy
    print *screenx
    print *screeny
    cont
  end

只是第一行的 set height 0 是手動加上去的,目的是不要訊息過長就停下來。

下次再使用 GDB 時就可以執行 source 載入使用。

(gdb) source break.cmd 
Breakpoint 1 at 0x7fedc71d1140: file ../../dix/getevents.c, line 940.
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00007fedc71d1140 in positionSprite at ../../dix/getevents.c:940
        print *devx
        print *devy
        print *screenx
        print *screeny
        cont

只是前面有一個找不到原始碼的小問題,可以執行以下指令來下載原始碼:

$ apt-get source xserver-xorg-core-lts-quantal
或是:
$ pull-lp-source xorg-server-lts-quantal precise

然後再執行:

$ sudo gdb /usr/bin/Xorg 1044 -d xorg-server-lts-quantal-1.13.0

最後 GDB 有其它的 Frontend 可以使用,像是 cgdb 以及 ddd 在這裡就不多提了。

張貼留言