2013/08/01

Debug Xorg with GDB on Ubuntu



在 Ubuntu 上要用 GDB 除錯那些用 apt-get install 安裝的程式十分的容易:1) 安裝 symbols, 2) 打開 GDB。這篇文章以除錯 Xorg 的 evdev 為例,evdev 是 Xorg 的 input driver 之一,它的主要功能是向 Xorg 送出一些鍵盤的按鍵,這篇主要會說明如何用 GDB 在送出 key 之前增加斷點。

實驗環境如下:

  • OS: Ubuntu 12.04 LTS
  • Kernel: 3.2.0-34-generic #53-Ubuntu
  • xserver-xorg-core: 2:1.11.4-0ubuntu10.13
  • xserver-xorg-input-evdev: 1:2.7.0-0ubuntu1.2


前情提要


本來只是除錯 trackpad (觸碰板)的一些行為,這類的工具很多像是

  • xinput
  • xev
  • lsinput
  • input-event
  • evtest

但是準備要用 input-event and evtest,卻發生 Operation not permit,也沒想到要怎麼解只好開始用 GDB。

設定 debug symbol 來源


完全從這裡抄來的, DebuggingProgramCrash,

$ echo "deb http://ddebs.ubuntu.com 1(lsb_release -cs) main restricted universe multiverse"  \
sudo tee -a /etc/apt/sources.list.d/ddebs.list

Stable releases (not alphas and betas) require three more lines adding to the same file, which is done by the following terminal command:

$ echo "deb http://ddebs.ubuntu.com 1(lsb_release -cs)-updates main restricted universe multiverse
deb http://ddebs.ubuntu.com 1(lsb_release -cs)-security main restricted universe multiverse
deb http://ddebs.ubuntu.com 1(lsb_release -cs)-proposed main restricted universe multiverse"  \
sudo tee -a /etc/apt/sources.list.d/ddebs.list
$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 428D7C01
$ sudo apt-get update

尋找要安裝的 symbol packages


先用 lsof 找到要除錯的 evdev_drv.so 是那支程式在用:

sudo lsof /usr/lib/xorg/modules/input/evdev_drv.so
lsof: WARNING: can't stat() fuse.gvfs-fuse-daemon file system /home/u/.gvfs
      Output information may be incomplete.
COMMAND  PID USER  FD   TYPE DEVICE SIZE/OFF    NODE NAME
Xorg    1603 root mem    REG    8,3    57000 1572945 /usr/lib/xorg/modules/input/evdev_drv.so

接著再看看是那個 packages 提供:

$ dpkg -S /usr/bin/Xorg
xserver-xorg-core: /usr/bin/Xorg

最後就安裝他們的 dbgsym,順便也把 source code 抓下來:

$ sudo apt-get install xserver-xorg-core-dbgsym xserver-xorg-input-evdev-dbgsym
$ apt-get source xserver-xorg-core xserver-xorg-input-evdev

除錯


由於使用 GDB 除錯 Xorg 會造成整個畫面都暫停,請用 ssh 連到 target 再開啟 GDB。

用 cgdb 指定除錯程式及其 PID。正常載入 symbols 應該會有 reading symbols ... done 那行。

$ sudo cgdb -- /usr/bin/Xorg `pidof X`
Reading symbols from /usr/lib/xorg/modules/input/evdev_drv.so...Reading symbols from /usr/lib/debug/usr/lib/xorg/modules/input/evdev_drv.so...done.

設定源碼路徑

(gdb) directory xserver-xorg-input-evdev-2.7.0/src
Source directories searched: /home/u/xorg/xserver-xorg-input-evdev-2.7.0/src:1cdir:1cwd

以 cgdb 為例,設完中斷點如下,如上圖:

(gdb)
Breakpoint 1 at 0x7fb2407a9959: file ../../src/evdev.c, line 360.

針對這個中斷點設定一些 messages,再使其繼續執行。

(gdb) commands 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>printf "0x%X, 0x%X", code, value
>c
>end
(gdb) c

接著在測試主機上按 asd,就會有如下訊息丟出來。它輸出 2 個數字,第一個是 kernel 回報的 event code,第二個數字應該是 key press/release。

Continuing.

Breakpoint 1, EvdevQueueKbdEvent (pInfo=0x7fb2477a0010, ev=0x7fffc5cd0548, value=1) at ../../src/evdev.c:360
0x26, 0x1
Breakpoint 1, EvdevQueueKbdEvent (pInfo=0x7fb2477a0010, ev=0x7fffc5cd0548, value=0) at ../../src/evdev.c:360
0x26, 0x0
Breakpoint 1, EvdevQueueKbdEvent (pInfo=0x7fb2477a0010, ev=0x7fffc5cd0548, value=1) at ../../src/evdev.c:360
0x27, 0x1
Breakpoint 1, EvdevQueueKbdEvent (pInfo=0x7fb2477a0010, ev=0x7fffc5cd0548, value=0) at ../../src/evdev.c:360
0x27, 0x0
Breakpoint 1, EvdevQueueKbdEvent (pInfo=0x7fb2477a0010, ev=0x7fffc5cd0548, value=1) at ../../src/evdev.c:360
0x28, 0x1
Breakpoint 1, EvdevQueueKbdEvent (pInfo=0x7fb2477a0010, ev=0x7fffc5cd0548, value=0) at ../../src/evdev.c:360
0x28, 0x0

其中,回報的 event code 可以用 xmodmap 看到列表:

$ xmodmap -pke  grep -A 3 ' 38 ='
No protocol specified
keycode  38 = a A a A
keycode  39 = s S s S
keycode  40 = d D d D
keycode  41 = f F f F

evtest 也可以,但是要 +8

$ sudo evtest /dev/input/event2
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x4ca product 0x4b version 0x110
Input device name: "Lite-On Technology Corp. USB Keyboard"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 1 (KEY_ESC)
    Event code 2 (KEY_1)
    Event code 3 (KEY_2)
    Event code 4 (KEY_3)
    Event code 5 (KEY_4)
    Event code 6 (KEY_5)
    Event code 7 (KEY_6)
    Event code 8 (KEY_7)
    Event code 9 (KEY_8)
    Event code 10 (KEY_9)
    Event code 11 (KEY_0)
    Event code 12 (KEY_MINUS)
    Event code 13 (KEY_EQUAL)
    Event code 14 (KEY_BACKSPACE)
    Event code 15 (KEY_TAB)
    Event code 16 (KEY_Q)
    Event code 17 (KEY_W)
    Event code 18 (KEY_E)
    Event code 19 (KEY_R)
    Event code 20 (KEY_T)
    Event code 21 (KEY_Y)
    Event code 22 (KEY_U)
    Event code 23 (KEY_I)
    Event code 24 (KEY_O)
    Event code 25 (KEY_P)
    Event code 26 (KEY_LEFTBRACE)
    Event code 27 (KEY_RIGHTBRACE)
    Event code 28 (KEY_ENTER)
    Event code 29 (KEY_LEFTCTRL)
    Event code 30 (KEY_A)

vim gdb plugin - pyclewn and dbgsym


(8/5 update)

習慣用 debug 可以用 pyclewn 當作介面,參考我之前介紹的文章

若是需要自己編譯的 deb 也有 dbgysm 的話由這篇文章提到,可以 1) 安裝 pkg-create-dbgsym 或 2)修改 debian/rules。

No comments: