搭建Linux2.6內(nèi)核調(diào)試環(huán)境

前言

最近在讀《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》炉菲,在書的開始就要先搭建一個(gè)Linux2.6的環(huán)境。
為了把環(huán)境搭好坤溃,折騰了好幾天拍霜。所以來分享一下搭建流程以及可能遇到的坑。

基礎(chǔ)環(huán)境說明

操作系統(tǒng)(虛擬機(jī)): ubuntu-14.04 64bit (ubuntu-14.04.6-server-amd64)
Linux內(nèi)核: 2.6.26
qemu: 2.0.0
busybox: 1.20.1
gcc: 4.8.4

這里是用虛擬機(jī)啟動(dòng)ubuntu進(jìn)行編譯薪介,然后使用busybox制作根文件系統(tǒng)祠饺,最后用qemu模擬器來啟動(dòng)編譯好的Linux。
強(qiáng)烈建議使用上述相同的環(huán)境進(jìn)行編譯汁政,不然會(huì)遇到很多坑道偷。個(gè)人覺得入門的時(shí)候沒必要把時(shí)間浪費(fèi)在這上面。

這里編譯的Linux內(nèi)核是32位的记劈,原因是在使用這個(gè)版本的qemu和gdb在調(diào)試64位系統(tǒng)的時(shí)候會(huì)遇到bug勺鸦。
當(dāng)然直接選擇32位的ubuntu也是可以的,編譯的時(shí)候會(huì)更簡單目木,不過我用的vscode remote不支持連接32位系統(tǒng)换途。

有興趣可以了解下什么是根文件系統(tǒng)

下文主要介紹Mac下的安裝流程,Windows/Linux環(huán)境下也大致一樣刽射。

搭建流程在Windows和Mac環(huán)境下都完成過怀跛。

系統(tǒng)環(huán)境安裝

  1. 使用vagrant創(chuàng)建虛擬機(jī)

vagrant 是一個(gè)虛擬機(jī)管理軟件,可以簡化虛擬機(jī)的創(chuàng)建和銷毀流程柄冲。它實(shí)際上還是使用virtualbox創(chuàng)建虛擬機(jī)吻谋。如果不想使用vagrant,可以直接使用virtualbox/vmware现横。

$ echo """Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/trusty64"
  config.vm.box_check_update = false
  config.vm.network "private_network", ip: "192.168.33.100"
  config.vm.provider "virtualbox" do |vb|
    vb.cpus = 2
    vb.memory = "1024"
  end
end
""" > Vagrantfile

$ vagrant up
$ vagrant ssh
$ sudo su

下面默認(rèn)使用root權(quán)限進(jìn)行所有操作

  1. 替換國內(nèi)軟件源(阿里源)
$ cd /etc/apt
$ cp sources.list sources.backup
$ echo """
deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse
""" > sources.list
$ apt-get update
  1. 安裝編譯環(huán)境
$ apt-get install -y libncurses5-dev build-essential
$ apt-get install -y lib32readline-gplv2-dev # 編譯32位系統(tǒng)
  1. 安裝調(diào)試環(huán)境
apt-get install -y qemu-system-x86 gdb
  1. 下載linux和busybox
$ mkdir linux
$ cd linux
$ wget https://www.busybox.net/downloads/busybox-1.20.1.tar.bz2
$ wget https://mirrors.edge.kernel.org/pub/linux/kernel/v2.6/linux-2.6.26.tar.bz2
$ tar -xf busybox-1.20.1.tar.bz2
$ tar -xf linux-2.6.26.tar.bz2

Linux編譯

  1. 打patch
    在linux-2.6.26文件夾下創(chuàng)建文件fix.patch漓拾,復(fù)制以下內(nèi)容
diff -Naur linux-2.6.26/arch/x86/lib/copy_user_64.S linux-2.6.26-2/arch/x86/lib/copy_user_64.S
--- linux-2.6.26/arch/x86/lib/copy_user_64.S    2008-07-13 21:51:29.000000000 +0000
+++ linux-2.6.26-2/arch/x86/lib/copy_user_64.S  2021-04-22 07:04:49.894796787 +0000
@@ -341,7 +341,7 @@
 11:    pop %rax
 7: ret
    CFI_ENDPROC
-END(copy_user_generic_c)
+END(copy_user_generic_string)
 
    .section __ex_table,"a"
    .quad 1b,3b
diff -Naur linux-2.6.26/arch/x86/vdso/Makefile linux-2.6.26-2/arch/x86/vdso/Makefile
--- linux-2.6.26/arch/x86/vdso/Makefile 2008-07-13 21:51:29.000000000 +0000
+++ linux-2.6.26-2/arch/x86/vdso/Makefile   2021-04-22 07:05:29.090798510 +0000
@@ -25,7 +25,7 @@
 
 export CPPFLAGS_vdso.lds += -P -C
 
-VDSO_LDFLAGS_vdso.lds = -m elf_x86_64 -Wl,-soname=linux-vdso.so.1 \
+VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \
                -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
 
 $(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so
@@ -69,7 +69,7 @@
 vdso32-images          = $(vdso32.so-y:%=vdso32-%.so)
 
 CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds)
-VDSO_LDFLAGS_vdso32.lds = -m elf_i386 -Wl,-soname=linux-gate.so.1
+VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-soname=linux-gate.so.1
 
 # This makes sure the $(obj) subdirectory exists even though vdso32/
 # is not a kbuild sub-make subdirectory.
diff -Naur linux-2.6.26/kernel/mutex.c linux-2.6.26-2/kernel/mutex.c
--- linux-2.6.26/kernel/mutex.c 2008-07-13 21:51:29.000000000 +0000
+++ linux-2.6.26-2/kernel/mutex.c   2021-04-22 07:06:51.646802139 +0000
@@ -58,7 +58,7 @@
  * We also put the fastpath first in the kernel image, to make sure the
  * branch is predicted by the CPU as default-untaken.
  */
-static void noinline __sched
+static __used void noinline __sched
 __mutex_lock_slowpath(atomic_t *lock_count);
 
 /***
@@ -95,7 +95,7 @@
 EXPORT_SYMBOL(mutex_lock);
 #endif
 
-static noinline void __sched __mutex_unlock_slowpath(atomic_t *lock_count);
+static __used noinline void __sched __mutex_unlock_slowpath(atomic_t *lock_count);
 
 /***
  * mutex_unlock - release the mutex
@@ -270,7 +270,7 @@
 /*
  * Release the lock, slowpath:
  */
-static noinline void
+static __used noinline void
 __mutex_unlock_slowpath(atomic_t *lock_count)
 {
    __mutex_unlock_common_slowpath(lock_count, 1);
@@ -315,7 +315,7 @@
 }
 EXPORT_SYMBOL(mutex_lock_killable);
 
-static noinline void __sched
+static __used noinline void __sched
 __mutex_lock_slowpath(atomic_t *lock_count)
 {
    struct mutex *lock = container_of(lock_count, struct mutex, count);
diff -Naur linux-2.6.26/Makefile linux-2.6.26-2/Makefile
--- linux-2.6.26/Makefile   2008-07-13 21:51:29.000000000 +0000
+++ linux-2.6.26-2/Makefile 2021-04-22 07:03:43.150793853 +0000
@@ -214,8 +214,8 @@
 
 HOSTCC       = gcc
 HOSTCXX      = g++
-HOSTCFLAGS   = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
-HOSTCXXFLAGS = -O2
+HOSTCFLAGS   = -Wall -Wstrict-prototypes -O1 -fomit-frame-pointer
+HOSTCXXFLAGS = -O1
 
 # Decide whether to build built-in, modular, or both.
 # Normally, just do built-in.
@@ -502,9 +502,9 @@
 all: vmlinux
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-KBUILD_CFLAGS  += -Os
+KBUILD_CFLAGS  += -O1
 else
-KBUILD_CFLAGS  += -O2
+KBUILD_CFLAGS  += -O1
 endif
 
 ifneq (CONFIG_FRAME_WARN,0)

$ patch -p1 < fix.patch

如果patch提示失敗,有可能是因?yàn)榘裦ix.patch里面的tab轉(zhuǎn)化成空格了戒祠,這時(shí)候你可以按照上面的內(nèi)容直接修改源文件骇两。

  1. 設(shè)置編譯配置
$ make ARCH=i386 defconfig
$ make ARCH=i386 menuconfig

如果提示
Your display is too small to run Menuconfig! It must be at least 19 lines by 80 columns.
那就說明你的命令行窗口太小,最好切到全屏姜盈,再重新配置

開啟debug信息選項(xiàng)

選擇界面上下進(jìn)行移動(dòng)低千,tab切換下方選項(xiàng)


  1. 開啟編譯
$ make ARCH=i386 -j2 

-jN 代表多任務(wù)并行化,數(shù)字一般為cpu核數(shù)*2

編譯成功后顯示

Root device is (252, 0)
Setup is 12288 bytes (padded to 12288 bytes).
System is 2844 kB
CRC 31a57b1f
Kernel: arch/x86/boot/bzImage is ready  (#1)

編譯時(shí)長跟機(jī)器配置有關(guān),一般幾分鐘到十幾分鐘示血。
我用的是18款的mbp 2.2 GHz 六核I7棋傍,創(chuàng)建的虛擬機(jī)是4核,編譯用時(shí)5m10s难审。
如果覺得編譯速度太慢瘫拣,有以下幾種方法可以加快速度:

  1. 改變虛擬機(jī)的核數(shù),加大-jN的數(shù)目告喊;
  2. 使用tmpfs文件系統(tǒng)麸拄,將代碼直接放到內(nèi)存中;
  3. 使用ccache緩存每次編譯的結(jié)果黔姜。

創(chuàng)建根文件系統(tǒng)

  1. 制作鏡像
$ cd ..
$ dd if=/dev/zero of=initrd.img count=1024 bs=4096
$ mkfs.ext2 initrd.img
$ mkdir rootfs
$ mount -o loop initrd.img rootfs/
  1. 創(chuàng)建字符設(shè)備
$ mkdir rootfs/dev
$ mknod rootfs/dev/console c 5 1
$ mknod rootfs/dev/ram b 1 0
  1. 打patch
$ cd busybox-1.20.1
$ echo """diff -Naur busybox-1.20.1/include/libbb.h busybox-1.20.1-2/include/libbb.h
--- busybox-1.20.1/include/libbb.h  2012-05-28 00:46:41.000000000 +0000
+++ busybox-1.20.1-2/include/libbb.h    2021-04-21 07:55:27.526183582 +0000
@@ -12,6 +12,8 @@

 #include "platform.h"

+
+#include <sys/resource.h>
 #include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
""" > fix.patch
$ patch -p1 < fix.patch
  1. 修改Makefile

vi中輸入292G 跳到292行拢切,在最后加上-m32

$ vi Makefilie
CC              = $(CROSS_COMPILE)gcc -m32
  1. 設(shè)置編譯選項(xiàng)
$ make defconfig
$ make menuconfig

選擇靜態(tài)鏈接



關(guān)閉shell → job contorl選項(xiàng)



  1. 編譯安裝busybox
$ make -j2
$ make CONFIG_PREFIX=../rootfs install

安裝完成后,可以在rootfs目錄看到

$ cd ..
$ ls -lah rootfs/
total 20
drwxr-xr-x 5 root root 4096 Apr 21 08:05 ./
drwxr-xr-x 7 root root 4096 Apr 21 08:05 ../
drwxr-xr-x 2 root root 4096 Apr 21 08:05 bin/
lrwxrwxrwx 1 root root   11 Apr 21 08:05 linuxrc -> bin/busybox*
drwxr-xr-x 2 root root 4096 Apr 21 08:05 sbin/
drwxr-xr-x 4 root root 4096 Apr 21 08:05 usr/
  1. 最后卸載rootfs
$ umount rootfs

啟動(dòng)系統(tǒng)

$ qemu-system-x86_64 \
-nographic \
-kernel ./linux-2.6.26/arch/x86/boot/bzImage \
-initrd ./initrd.img \
-append "root=/dev/ram init=/bin/sh console=ttyS0"

使用Ctrl a+x來退出qemu

input: ImExPS/2 Generic Explorer Mouse as /class/input/input2
RAMDISK: ext2 filesystem found at block 0
RAMDISK: Loading 4096KiB [1 disk] into ram disk... done.
VFS: Mounted root (ext2 filesystem) readonly.
Freeing unused kernel memory: 448k freed
/ #
VFS: Mounted root (ext2 filesystem) readonly.
Freeing unused kernel memory: 448k freed
Warning: unable to open an initial console.
Failed to execute /bin/ash.  Attempting defaults...
Kernel panic - not syncing: No init found.  Try passing init= option to kernel.

如果遇到這個(gè)錯(cuò)誤秆吵,一般是根文件系統(tǒng)沒創(chuàng)建對(duì)失球,請(qǐng)根據(jù)上面的步驟重新創(chuàng)建一遍。

VFS: Mounted root (ext2 filesystem) readonly.
Freeing unused kernel memory: 448k freed

如果提示VFS錯(cuò)誤帮毁,則是Linux內(nèi)核編譯的時(shí)候沒有開啟ext2的配置,可以回到make menuconfig中開啟這個(gè)選項(xiàng)豺撑。

/bin/ash: can't access tty; job control turned off

如果提示job control烈疚,則需要回到busygox編譯那里關(guān)閉這個(gè)選項(xiàng)。

GDB Debug

  1. 開啟debug選項(xiàng)
$ qemu-system-x86_64 \
-nographic \
-kernel ./linux-2.6.26/arch/x86/boot/bzImage \
-initrd ./initrd.img \
-append "root=/dev/ram init=/bin/ash console=ttyS0" -s -S
  1. 開啟gdb
    在另外一個(gè)終端開啟
$ cd linux
$ gdb --dir=./linux-2.6.26
(gdb) file linux-2.6.26/vmlinux
(gdb) target remote :1234
(gdb) hb start_kernel
(gdb) c

gdb -tui 可以開啟窗口實(shí)時(shí)查看代碼
只有使用hb才能打斷點(diǎn)聪轿,這是gdb的bug導(dǎo)致的gdbserver inside qemu does not stop on breakpoints

覺得每次輸入file和targer麻煩的爷肝,可以創(chuàng)建gdb的默認(rèn)啟動(dòng)命令

$ echo """
file linux-2.6.26/vmlinux
target remote :1234
""" > /root/.gdbinit 
$ echo """
set auto-load safe-path /
""" > .gdbinit

Vscode

如果你是使用vscode瀏覽源碼,可以參考這個(gè)文章vscode在linux下搭建內(nèi)核驅(qū)動(dòng)開發(fā)環(huán)境

參考鏈接:

學(xué)習(xí)ulk3,搭建linux2.6內(nèi)核的調(diào)試環(huán)境
elf_i386或elf_x86_64:沒有那個(gè)文件或目錄 解決方法
內(nèi)核2.6.22.6編譯出現(xiàn) undefined reference to __mutex_unlock_slowpath
linux 內(nèi)核編譯錯(cuò)誤 .size expression for copy_user_generic_c does not evaluate to a constant

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陆错,一起剝皮案震驚了整個(gè)濱河市灯抛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌音瓷,老刑警劉巖对嚼,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異绳慎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門堪伍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驼仪,“玉大人,你說我怎么就攤上這事珊楼⊥ㄑ辏” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵厕宗,是天一觀的道長画舌。 經(jīng)常有香客問我堕担,道長,這世上最難降的妖魔是什么骗炉? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任照宝,我火速辦了婚禮,結(jié)果婚禮上句葵,老公的妹妹穿的比我還像新娘厕鹃。我一直安慰自己,他們只是感情好乍丈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布剂碴。 她就那樣靜靜地躺著,像睡著了一般轻专。 火紅的嫁衣襯著肌膚如雪忆矛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天请垛,我揣著相機(jī)與錄音催训,去河邊找鬼。 笑死宗收,一個(gè)胖子當(dāng)著我的面吹牛漫拭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播混稽,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼采驻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了匈勋?” 一聲冷哼從身側(cè)響起礼旅,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎洽洁,沒想到半個(gè)月后痘系,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饿自,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年碎浇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片璃俗。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奴璃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出城豁,到底是詐尸還是另有隱情苟穆,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站雳旅,受9級(jí)特大地震影響跟磨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜攒盈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一抵拘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧型豁,春花似錦僵蛛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至衣形,卻和暖如春驼侠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谆吴。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國打工倒源, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人句狼。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓笋熬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鲜锚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容