1. 程式人生 > 其它 >手把手教你利用VS Code+Qemu+GDB除錯Linux核心

手把手教你利用VS Code+Qemu+GDB除錯Linux核心

背景

一直以來,都對linux系統的理解都是在應用層面,看過了《UNIX環境高階程式設計》,對於系統中的一些模組的實現方法還缺乏深刻的認識,故想研究下Linux核心機制。

單純閱讀原始碼還是不如一步一步除錯核心理解深刻,對於除錯核心的方法,網上也有不少,主要是利用Qemu+GDB對核心進行除錯,但網上的資料大多零散,步驟記錄不夠詳細,筆者在實現過程中走了很多彎路,而且直接利用GDB除錯檢視程式碼還不甚方便,所以這裡使用VS Code+Qemu+GDB來進行Linux核心除錯,記錄過程中的主要步驟。

環境

由於個人主機是MacOS 10.14.5,所以在Parrales Desktop虛擬機器使用Ubuntu 14.04 amd64搭建核心除錯環境。

若主機本身就是Linux系統,則無需安裝虛擬機器,可直接進行核心除錯環境的搭建,效能更佳。

主要步驟

概述

  1. 虛擬機器(Parrales Desktop,vmware等均可)中安裝Ubuntu(如果主機本身就是Linux系統,本步驟可略)
  2. 下載linux kernel,編譯生成bzImage
  3. 更新GCC,G++,GDB
  4. 安裝Qemu
  5. 安裝VS Code,並進行相關配置

虛擬機器Ubuntu安裝

虛擬機器(Parrales Desktop,vmware等均可)中安裝Ubuntu 14.04,這裡Ubuntu版本可以自由選擇,只要Parrales tools能夠正常安裝即可。

另外,最好選擇x64版本,效能會更好一些。具體安裝過程略。 由於原始apt更新速度較慢,需要更新國內源,這裡使用清華apt源

vim /etc/apt/sources.list

清華apt源

核心編譯

#安裝編譯相關依賴
apt-get install libncurses5-dev libssl-dev bison flex libelf-dev gcc make openssl libc6-dev

#這裡選擇清華源,國內速度會快很多
wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v4.x/linux-4.5.tar.gz

#解壓
tar -xvf linux-4.5.tar.gz

cd  linux-4.5
#配置編譯選項,這裡可以進行核心編譯的各種配置,由於預設已經勾選了除錯相關的配置,可直接esc退出儲存
make menuconfig
#開始多執行緒編譯,首次此步會等待較長時間,後續由於已經生成了中間檔案,速度會變快
make -j8

編譯完成後,目錄下會生成以下

./vmLinux

./arch/x86/boot/bzImage

其中vmLinux為GDB所需的除錯Map檔案,bzImage為大核心檔案

如果需要安裝核心可以進行以下步驟(此步非必須)

#如果需要安裝核心,
make modules_install
make install

安裝後,重啟主機,可以在Grub中選擇新的核心。

更新GCC,G++,GDB

由於系統預設的GDB在除錯核心時會出現“Remote ‘g’ packet reply is too long”的錯誤,我們需要修改GDB的原始碼,而編譯新版的GDB原始碼需要新版的GCC和G++,故需要更新以下:

#安裝GCC-9,G++-9
sudo apt install software-properties-common
sudo apt-get update
sudo apt install gcc-9 g++-9
#安裝後執行
gcc -v
#若是新版本gcc,則完成,若非新版本,需要將gcc連結到gcc-9

編譯安裝GDB

#下載GDB,這裡使用北交的gnu源,國內速度會快很多
wget https://mirror.bjtu.edu.cn/gnu/gdb/gdb-8.3.tar.xz
tar -xvf gdb-8.3.tar.xz

#在gdb/remote.c檔案下作如下修改
    /* Further sanity checks, with knowledge of the architecture.  */
    // if (buf_len > 2 * rsa->sizeof_g_packet)
    //   error (_("Remote 'g' packet reply is too long (expected %ld bytes, got %d "
    //      "bytes): %s"),
    //    rsa->sizeof_g_packet, buf_len / 2,
    //    rs->buf.data ());
  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
./configure
./make -j8
sudo ./make install
#開啟GDB,看是否為新版本
gdb

Qemu配置

#安裝qemu
apt-get install qemu

製作helloworld的rootfs用於測試

touch main.c

鍵入以下程式碼

#include <stdio>
int main()
{
    printf("hello world!");
    printf("hello world!");
    printf("hello world!");
    printf("hello world!");
    fflush(stdout);
    while(1);
    return 0;
}

編譯

gcc --static -o helloworld main.c
echo helloworld | cpio -o --format=newc > rootfs

Qemu直接執行測試(非必須)

qemu-system-x86_64 \
    -kernel ./arch/x86/boot/bzImage \
    -initrd ./rootfs \
    -append "root=/dev/ram rdinit=/helloworld"

Qemu 開啟GDB除錯

qemu-system-x86_64  \
 -kernel ./arch/x86/boot/bzImage  \
 -initrd ./rootfs  \
 -append "root=/dev/ram rdinit=/helloworld" \
 -smp 2  \
 -s -S

進行以上會開啟Qemu並進入等待除錯狀態,此時可以直接gdb除錯,如下(非必須)

gdb ./vmLinux
#以下進行除錯
target remote:1234
b start_kernel
c

可以發現核心被斷點在start_kernel函式上

VS code配置

官網下載安裝vscode:https://code.visualstudio.com

1. vscode開啟kernel原始碼資料夾

2. 安裝gdb debug外掛

3. Debug->Open Configurations,做以下配置

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "kernel-debug",
            "type": "cppdbg",
            "request": "launch",
            "miDebuggerServerAddress": "127.0.0.1:1234",
            "program": "${workspaceFolder}/vmlinux",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "logging": {
                "engineLogging": false
            },
            "MIMode": "gdb",
        }
    ]
    }

此時將斷點設在init/main.c中的start_kernel函式中,然後Qemu 開啟手機號碼轉讓地圖GDB除錯,vscode start debug即可開始除錯核心。