1. 程式人生 > >gdb除錯linux系統呼叫

gdb除錯linux系統呼叫

下載並編譯核心

首先進行核心編譯,在核心原始碼路徑下執行:

sudo apt-get install m4 libncurses5-dev -y

make menuconfig(選中
          kernel hacking –> Kernel debugging
          kernel hacking –> Compile-time checks and compiler options  –> compile the kernel with debug info
          kernel hacking –> Compile-time
checks and compiler options -> compile the kernel with frame pointers make

拷貝bzImage到我們用來除錯的目錄,如/opt/kernel-debug

mkdir -p /opt/kernel-debug
cp arch/x86/boot/bzImage /opt/kernel-debug

製作busybox所需要的rootfs

執行以下命令在/opt/kernel-debug下建立rootfs

cd /opt/kernel-debug
dd if=/dev/zero of=rootfs.img bs=1M count=10
mkfs.ext3 rootfs.img mkdir rootfs # 將其mount 到新建立到目錄上 mount -t ext3 -o loop rootfs.img rootfs cd rootfs mkdir dev proc sys

安裝qemu

下載qemu-1.3.0.tar.bz2到指定目錄

  • 安裝依賴包
apt-get install build-essential libtool automake \
libgmp-dev libnspr4-dev libnss3-dev openssl \
libssl-dev git iasl glib-2.0 libglib2.0
-0 \ libglib2.0-dev libtasn1-6-dev tpm-tools \ libfuse-dev libgnutls-dev libsdl1.2-dev \ expect gawk socat libfdt-dev

編譯qemu

tar -xjvf qemu-1.3.0.tar.bz2
cd qemu-1.3.0
./configure --enable-kvm --enable-sdl --target-list=x86_64-softmmu
make
make install

安裝busybox

wget https://busybox.net/downloads/busybox-1.26.1.tar.bz2
tar -xjvf busybox-1.26.1.tar.bz2
cd busybox-1.26.1
make menuconfig
    - 選擇靜態編譯:Busybox Settings->Build Busybox as a static binary
    - 取消選擇Networking utilities->iptunnel (NEW)
    - 取消選擇Networking utilities->inetd
make

安裝到bzImage下的rootfs下

make install CONFIG_PREFIX=/opt/kernel-debug/rootfs

unmount rootfs

cd /opt/kernel-debug
sudo umount rootfs

啟動qemu進行除錯

啟動qemu

cd /opt/kernel-debug
qemu-system-x86_64  -S -kernel bzImage -hda rootfs.img -append "root=/dev/sda init=/bin/ash"

用滑鼠點選qemu視窗,然後ctrl+alt+2切換到控制檯,輸入gdbserver tcp::1234

開啟另外一個終端,安裝ddd,並執行ddd vmlinux

apt-get install ddd
# 進入linux原始碼路徑,本文路徑為/usr/src/linux-3.13-obj
cd /usr/src/linux-3.13-obj
ddd vmlinux

介面為:

這裡寫圖片描述

在gdb的命令列中輸入命令target remote localhost:1234將qemu虛擬機器連線到ddd的控制檯
自此就可以通過ddd的控制檯用gdb的命令來檢視原始碼的執行資訊了

在gdb命令中輸入continue,出現錯誤:

(gdb) continue
Continuing.
Continuing.
Remote 'g' packet reply is too long: edffffff00000000ffffffffffffffff0000000000000001000000000000000000000000000000004600000000000000b81ec081ffffffffb81ec081ffffffff000000000000000000000000000000002900000000000000689eea81ffffffff0000000000000000d81fc081ffffffffc022dd81ffffffffd81fc081ffffffff86050581ffffffff8602000010000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f030000000000000000000000000000000000000000000000000000000000000000ff0000000000000000000000000020202020202020202020202020202020000000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff00000000000000000000ff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff00000000000000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000
(gdb) Quit

解決方案:

下載更高版本的gdb:

wget http://ftp.gnu.org/gnu/gdb/gdb-7.11.tar.gz
tar xzvf gdb-7.11.tar.gz
cd gdb-7.11
vim gdb/remote.c

註釋掉

if (buf_len > 2 * rsa->sizeof_g_packet)
     error (_(“Remote ‘g’ packet reply is too long: %s”), rs->buf);

在其後加上

if (buf_len > 2 * rsa->sizeof_g_packet) {
       rsa->sizeof_g_packet = buf_len;
       for (i = 0; i < gdbarch_num_regs (gdbarch); i++) { 
           if (rsa->regs[i].pnum == -1) 
               continue; 
           if (rsa->regs[i].offset >= rsa->sizeof_g_packet) 
               rsa->regs[i].in_g_packet = 0; 
           else 
              rsa->regs[i].in_g_packet = 1; 
     } 
}

安裝gdb

apt-get install texinfo
./configure
make
make install
mv /usr/bin/gdb /usr/bin/gdb.bak
ln -s /usr/local/bin/gdb /usr/bin/gdb

再重新 ddd vmlinux後,gdb介面裡顯示:

(gdb) target remote localhost:1234
Remote debugging using localhost:1234
native_safe_halt () at /usr/src/octa-blockIMA/octa-blockIMA/arch/x86/include/asm/irqflags.h:50
(gdb) 

除錯示例

在本機上寫一段程式:

root@BlockIMATest:~# cat fork.c
#include <stdio.h>

int main() {
    int fd;

    fd = fork();

    if(fd == 0) {
        printf("I am child\n");
    } else if(fd > 0) {
        printf("I am parenet\n");
    }
    return 0;
}
root@BlockIMATest:~# 

編譯成靜態的二進位制程式

gcc -c -g -static fork.c
gcc -o test_fork -static fork.o

將該二進位制拷貝到/opt/kernel-debug/rootfs/bin

cd /opt/kernel-debug
# 將其mount 到rootfs上
mount -t ext3 -o loop rootfs.img rootfs
cd rootfs
cp ~/test_fork /opt/kernel-debug/rootfs/bin/
cd ../
sudo umount rootfs

啟動qemu

cd /opt/kernel-debug
qemu-system-x86_64  -S -kernel bzImage -hda rootfs.img -append "root=/dev/sda init=/bin/ash"

用滑鼠點選qemu視窗,然後ctrl+alt+2切換到控制檯,輸入gdbserver tcp::1234

另開一個終端,在核心目錄下啟動ddd vmlinux

在gdb裡連線到qemu,讓其執行

GNU DDD 3.3.12 (x86_64-pc-linux-gnu), by Dorothea LReading symbols from vmlinux...done.
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x0000000000000000 in irq_stack_union ()
(gdb) continue
Continuing.

這裡寫圖片描述

在qemu視窗,使用ctrl+alt+1切換到虛擬機器介面,等待虛擬機器啟動。虛擬機器啟動成功後,在ddd介面裡source->Breakpoints裡新增一個斷點,在彈出的Set point at文字框中輸入do_fork

回到qemu視窗,執行test_fork,可以看到進入斷點了~

這裡寫圖片描述