1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        使用 GDB + Qemu 調(diào)試 Linux 內(nèi)核

        共 6287字,需瀏覽 13分鐘

         ·

        2021-02-09 19:15


        更多奇技淫巧歡迎訂閱博客:https://fuckcloudnative.io

        1. 概述

        在某些情況下,我們需要對(duì)于內(nèi)核中的流程進(jìn)行分析,雖然通過 BPF 的技術(shù)可以對(duì)于函數(shù)傳入的參數(shù)和返回結(jié)果進(jìn)行展示,但是在流程的調(diào)試上還是不如直接 GDB 單步調(diào)試來的直接。本文采用的編譯方式如下,在一臺(tái) 16 核 CentOS 7.7 的機(jī)器上進(jìn)行內(nèi)核源碼相關(guān)的編譯(主要是考慮編譯效率),調(diào)試則是基于 VirtualBox 的 Ubuntu 20.04 系統(tǒng)中,采用 Qemu + GDB 進(jìn)行單步調(diào)試,網(wǎng)上查看了很多文章,在最終進(jìn)行單步跟蹤的時(shí)候,始終不能夠在斷點(diǎn)處停止,進(jìn)行過多次嘗試和查詢文檔,最終發(fā)現(xiàn)需要在內(nèi)核啟動(dòng)參數(shù)上添加 nokaslr ,本文是對(duì)整個(gè)搭建過程的總結(jié)。

        2. Linux 內(nèi)核編譯和文件系統(tǒng)制作

        Linux 內(nèi)核編譯

        編譯內(nèi)核和制作文件系統(tǒng)在 CentOS 7.7 的機(jī)器上。源碼從國(guó)內(nèi)清華的源下載:http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/, 此處選擇 linux-4.19.172.tar.gz 版本。詳細(xì)編譯步驟如下:

        $?sudo?yum?group?install?"Development?Tools"
        $?yum?install?ncurses-devel?bison?flex?elfutils-libelf-devel?openssl-devel

        $?wget?http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/v4.x/linux-4.19.172.tar.gz
        $?tar?xzvf?linux-4.19.172.tar.gz
        $?cd?linux-4.19.172/
        $?make?menuconfig

        在內(nèi)核編譯選項(xiàng)中,開啟如下 “Compile the kernel with debug info”, 4.19.172 中默認(rèn)已經(jīng)選中:

        Kernel hacking —> Compile-time checks and compiler options —> [ ] Compile the kernel with debug info

        以上配置完成后會(huì)在當(dāng)前目錄生成 .config 文件,我們可以使用 grep 進(jìn)行驗(yàn)證:

        #?grep?CONFIG_DEBUG_INFO?.config
        CONFIG_DEBUG_INFO=y

        接著我們進(jìn)行內(nèi)核編譯:

        $?nproc???????#?查看當(dāng)前的系統(tǒng)核數(shù)
        $?make?-j?12??#?或者采用?make?bzImage?進(jìn)行編譯,?-j?N,表示使用多少核并行編譯

        #?未壓縮的內(nèi)核文件,這個(gè)在?gdb?的時(shí)候需要加載,用于讀取?symbol?符號(hào)信息,由于包含調(diào)試信息所以比較大
        $?ls?-hl?vmlinux
        -rwxr-xr-x?1?root?root?449M?Feb??3?14:46?vmlinux

        #?壓縮后的鏡像文件
        $?ls?-hl?./arch/x86_64/boot/bzImage
        lrwxrwxrwx?1?root?root?22?Feb??3?14:47?./arch/x86_64/boot/bzImage?->?../../x86/boot/bzImage

        $?ls?-hl?./arch/x86/boot/bzImage
        -rw-r--r--?1?root?root?7.6M?Feb??3?14:47?./arch/x86/boot/bzImage

        不同發(fā)行版本下的內(nèi)核的詳細(xì)編譯文檔可以參考這里[1]

        啟動(dòng)內(nèi)存文件系統(tǒng)制作

        #?首先安裝靜態(tài)依賴,否則會(huì)有報(bào)錯(cuò),參見后續(xù)的排錯(cuò)章節(jié)
        $?yum?install?-y?glibc-static.x86_64?-y

        $?wget?https://busybox.net/downloads/busybox-1.32.1.tar.bz2
        $?tar?-xvf?busybox-1.32.1.tar.bz2
        $?cd?busybox-1.32.1/

        $?make?menuconfig

        #?安裝完成后生成的相關(guān)文件會(huì)在?_install?目錄下
        $?make?&&?make?install

        $?cd?_install
        $?mkdir?proc
        $?mkdir?sys
        $?touch?init

        #??init?內(nèi)容見后續(xù)章節(jié),為內(nèi)核啟動(dòng)的初始化程序
        $?vim?init

        #?必須設(shè)置成可執(zhí)行文件
        $?chmod?+x?init

        $?find?.?|?cpio?-o?--format=newc?>?./rootfs.img
        cpio:?File?./rootfs.img?grew,?2758144?new?bytes?not?copied
        10777?blocks

        $?ls?-hl?rootfs.img
        -rw-r--r--?1?root?root?5.3M?Feb??2?11:23?rootfs.img

        其中上述的 init 文件內(nèi)容如下,打印啟動(dòng)日志和系統(tǒng)的整個(gè)啟動(dòng)過程花費(fèi)的時(shí)間:

        #!/bin/sh
        echo?"{==DBG==}?INIT?SCRIPT"
        mkdir?/tmp
        mount?-t?proc?none?/proc
        mount?-t?sysfs?none?/sys
        mount?-t?debugfs?none?/sys/kernel/debug
        mount?-t?tmpfs?none?/tmp

        mdev?-s
        echo?-e?"{==DBG==}?Boot?took?$(cut?-d'?'?-f1?/proc/uptime)?seconds"

        #?normal?user
        setsid?/bin/cttyhack?setuidgid?1000?/bin/sh

        到此為止我們已經(jīng)編譯了好了 Linux 內(nèi)核(vmlinux 和 bzImage)和啟動(dòng)的內(nèi)存文件系統(tǒng)(rootfs.img)。

        錯(cuò)誤排查

        在編譯過程中出現(xiàn)以下報(bào)錯(cuò):

        /bin/ld:?cannot?find?-lcrypt
        /bin/ld:?cannot?find?-lm
        /bin/ld:?cannot?find?-lresolv
        /bin/ld:?cannot?find?-lrt
        collect2:?error:?ld?returned?1?exit?status
        Note:?if?build?needs?additional?libraries,?put?them?in?CONFIG_EXTRA_LDLIBS.
        Example:?CONFIG_EXTRA_LDLIBS="pthread?dl?tirpc?audit?pam"

        出錯(cuò)的原因是因?yàn)槲覀儾捎渺o態(tài)編譯依賴的底層庫(kù)沒有安裝,如果不清楚這些庫(kù)有哪些 rpm 安裝包提供,則可以通過 yum provides 命令查看,然后安裝相關(guān)依賴包重新編譯即可。

        $?yum?provides?*/libm.a
        //?...
        glibc-static-2.17-317.el7.x86_64?:?C?library?static?libraries?for?-static?linking.
        Repo????????:?base
        Matched?from:
        Filename????:?/usr/lib64/libm.a

        3. Qemu 啟動(dòng)內(nèi)核

        在上述步驟準(zhǔn)備好以后,我們需要在調(diào)試的 Ubuntu 20.04 的系統(tǒng)中安裝 Qemu 工具,其中調(diào)測(cè)的 Ubuntu 系統(tǒng)使用 VirtualBox 安裝。

        $?apt?install?qemu?qemu-utils?qemu-kvm?virt-manager?libvirt-daemon-system?libvirt-clients?bridge-utils

        把上述編譯好的 vmlinux、bzImage、rootfs.img 和編譯的源碼拷貝到我們當(dāng)前 Unbuntu 機(jī)器中。

        拷貝 Linux 編譯的源碼主要是在 gdb 的調(diào)試過程中查看源碼,其中 vmlinux 和 linux 源碼處于相同的目錄,本例中 vmlinux 位于 linux-4.19.172 源目錄中。

        $?qemu-system-x86_64?-kernel?./bzImage?-initrd??./rootfs.img?-append?"nokaslr?console=ttyS0"?-s?-S?-nographic

        使用上述命令啟動(dòng)調(diào)試,啟動(dòng)后會(huì)停止在界面處,并等待遠(yuǎn)程 gdb 進(jìn)行調(diào)試,在使用 GDB 調(diào)試之前,可以先使用以下命令進(jìn)程測(cè)試內(nèi)核啟動(dòng)是否正常。

        $?qemu-system-x86_64?-kernel?./bzImage?-initrd??./rootfs.img?-append?"nokaslr?console=ttyS0"?-nographic

        其中命令行中各參數(shù)如下:

        • -kernel ./bzImage:指定啟用的內(nèi)核鏡像;
        • -initrd ./rootfs.img:指定啟動(dòng)的內(nèi)存文件系統(tǒng);
        • -append "nokaslr console=ttyS0" :附加參數(shù),其中 nokaslr 參數(shù)必須添加進(jìn)來,防止內(nèi)核起始地址隨機(jī)化,這樣會(huì)導(dǎo)致 gdb 斷點(diǎn)不能命中;參數(shù)說明可以參見這里[2]
        • -s :監(jiān)聽在 gdb 1234 端口;
        • -S :表示啟動(dòng)后就掛起,等待 gdb 連接;
        • -nographic:不啟動(dòng)圖形界面,調(diào)試信息輸出到終端與參數(shù) console=ttyS0 組合使用;

        4. GDB 調(diào)試

        在使用 qemu-system-x86_64 命令啟動(dòng)內(nèi)核以后,進(jìn)入到我們從編譯機(jī)器上拷貝過來的 Linux 內(nèi)核源代碼目錄中,在另外一個(gè)終端我們來啟動(dòng) gdb 命令:

        [linux-4.19.172]$?gdb
        (gdb)?file?vmlinux???????????#?vmlinux?位于目錄?linux-4.19.172?中
        (gdb)?target?remote?:1234
        (gdb)?break?start_kernel?????#?有些文檔建議使用?hb?硬件斷點(diǎn),我在本地測(cè)試使用?break?也是?ok?的
        (gdb)?c?????????????#?啟動(dòng)調(diào)試,則內(nèi)核會(huì)停止在?start_kernel?函數(shù)處

        整體運(yùn)行界面如下:

        5. Eclipse 圖像化調(diào)試

        我們可以通過 eclipse-cdt 進(jìn)行可視化項(xiàng)目調(diào)試。

        ”File“ -> “New” -> “Project” ,然后選擇 ”Makefile Project with Existing Code“ 選項(xiàng),后續(xù)按照向?qū)?dǎo)入代碼。

        在 “Run” -> “Debug Configurations” 選項(xiàng)中,創(chuàng)建一個(gè) ”C/C++ Attach to Application“ 的調(diào)試選項(xiàng)。

        • Project:選擇我們剛才創(chuàng)建的項(xiàng)目名字;
        • C/C++ Application:選擇編譯 Linux 內(nèi)核帶符號(hào)信息表的 vmlinux;
        • Build before launching:選擇 ”Disable auto build“;
        • Debugger:選擇 gdbserver,具體設(shè)置如下圖;
        • 在 Debugger 中的 Connection 信息中選擇 ”TCP“,并填寫端口為 ”1234“;

        啟動(dòng) Debug 調(diào)試,即可看到與 gdb 類似的窗口。

        啟動(dòng) ”Debug“ 調(diào)試以后的窗口如下,在 Debug 窗口欄中,設(shè)置與 gdb 調(diào)試相同的步驟即可。

        6. 參考

        • How to compile and install Linux Kernel 5.6.9 from source code[3]
        • 用 qemu + gdb 調(diào)試 linux 內(nèi)核[4] ***
        • QEMU+busybox 搭建 Linux 內(nèi)核運(yùn)行環(huán)境[5] ***
        • QEMU+gdb 調(diào)試 Linux 內(nèi)核全過程[6] *
        • linux 內(nèi)核編譯與調(diào)試方法[7]
        • How to Build A Custom Linux Kernel For Qemu (2015 Edition)[8]
        • qemu 與 qemu-kvm 到底什么區(qū)別[9]
        • 在 qemu 環(huán)境中用 gdb 調(diào)試 Linux 內(nèi)核[10] *

        參考資料

        [1]

        這里: https://www.cyberciti.biz/tips/compiling-linux-kernel-26.html

        [2]

        這里: https://www.zhihu.com/question/270476360

        [3]

        How to compile and install Linux Kernel 5.6.9 from source code: https://www.cyberciti.biz/tips/compiling-linux-kernel-26.html

        [4]

        用 qemu + gdb 調(diào)試 linux 內(nèi)核: https://www.jianshu.com/p/431d606d322c

        [5]

        QEMU+busybox 搭建 Linux 內(nèi)核運(yùn)行環(huán)境: https://www.sunxiaokong.xyz/2020-01-14/lzx-linuxkernel-qemuinit/

        [6]

        QEMU+gdb 調(diào)試 Linux 內(nèi)核全過程: https://blog.csdn.net/jasonLee_lijiaqi/article/details/80967912

        [7]

        linux 內(nèi)核編譯與調(diào)試方法: https://www.cnblogs.com/syw-casualet/p/5271369.html

        [8]

        How to Build A Custom Linux Kernel For Qemu (2015 Edition): http://mgalgs.github.io/2015/05/16/how-to-build-a-custom-linux-kernel-for-qemu-2015-edition.html

        [9]

        qemu 與 qemu-kvm 到底什么區(qū)別: https://www.cnblogs.com/hugetong/p/8808544.html

        [10]

        在 qemu 環(huán)境中用 gdb 調(diào)試 Linux 內(nèi)核: https://www.cnblogs.com/wipan/p/9264979.html


        原文鏈接:https://www.ebpf.top/post/qemu_gdb_busybox_debug_kernel/



        你可能還喜歡

        點(diǎn)擊下方圖片即可閱讀

        什么?WireGuard 可以讓躲在 NAT 后面的客戶端之間直連了??

        云原生是一種信仰???


        關(guān)注上面的公眾號(hào)

        后臺(tái)回復(fù)?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!



        點(diǎn)擊?"閱讀原文"?獲取更好的閱讀體驗(yàn)!

        ??給個(gè)「在看」,是對(duì)我最大的支持??
        瀏覽 58
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            深爱综合网 | 一道本在线视频 | 丁香五月v国产 | 真人操屄视频 | 天堂逼片| 美国式禁忌14观看中文 | 国产精品三级电影 | 美女插逼视频 | 免费看日产一区二区三区 | 亚洲免费在线视频观看 |