俗話說,工欲善其事 必先利其器。linux kernel是一個(gè)非常復(fù)雜的系統(tǒng),初學(xué)者會很難入門。
如果有一個(gè)方便的調(diào)試環(huán)境,學(xué)習(xí)效率至少能有5-10倍的提升。
為了學(xué)習(xí)linux內(nèi)核,通常有這兩個(gè)需要
- 可以擺脫硬件,方便的編譯和運(yùn)行l(wèi)inux
- 可以使用圖形化的工具來調(diào)試linux
筆者使用VSCode+GDB+Qemu完成了這兩個(gè)需求
qemu作為虛擬機(jī),用來啟動linux。
VSCode+GDB作為調(diào)試工具,用來圖形化地DEBUG。
最終效果大致如下:
qemu運(yùn)行界面:
vscode調(diào)試界面:
文章來源:http://www.zghlxwxcb.cn/news/detail-474441.html
下面將一步一步介紹如何搭建上述環(huán)境。
本文所有操作都在Vmware Ubuntu16虛擬機(jī)上進(jìn)行。
安裝編譯工具鏈
由于Ubuntu是X86架構(gòu),為了編譯arm64的文件,需要安裝交叉編譯工具鏈
sudo apt-get install gcc-aarch64-linux-gnu
sudo apt-get install libncurses5-dev build-essential git bison flex libssl-dev
制作根文件系統(tǒng)
linux的啟動需要配合根文件系統(tǒng),這里我們利用busybox來制作一個(gè)簡單的根文件系統(tǒng)
編譯busybox
wget https://busybox.net/downloads/busybox-1.33.1.tar.bz2
tar -xjf busybox-1.33.1.tar.bz2
cd busybox-1.33.1
打開靜態(tài)庫編譯選項(xiàng)
make menuconfig
Settings --->
[*] Build static binary (no shared libs)
指定編譯工具
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
編譯
make
make install
編譯完成,在busybox目錄下生成_install目錄
定制文件系統(tǒng)
為了init進(jìn)程能正常啟動, 需要再額外進(jìn)行一些配置
根目錄添加etc、dev和lib目錄
# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install [1:02:17]
$ mkdir etc dev lib
# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install [1:02:17]
$ ls
bin dev etc lib linuxrc sbin usr
在etc分別創(chuàng)建文件:
# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/etc [1:06:13]
$ cat profile
#!/bin/sh
export HOSTNAME=bryant
export USER=root
export HOME=/home
export PS1="[$USER@$HOSTNAME \W]\# "
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH
# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/etc [1:06:16]
$ cat inittab
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r
# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/etc [1:06:19]
$ cat fstab
#device mount-point type options dump fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
debugfs /sys/kernel/debug debugfs defaults 0 0
kmod_mount /mnt 9p trans=virtio 0 0
# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/etc [1:06:26]
$ ls init.d
rcS
# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/etc [1:06:30]
$ cat init.d/rcS
mkdir -p /sys
mkdir -p /tmp
mkdir -p /proc
mkdir -p /mnt
/bin/mount -a
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
這里對這幾個(gè)文件做一點(diǎn)說明:
- busybox 作為linuxrc啟動后, 會讀取/etc/profile, 這里面設(shè)置了一些環(huán)境變量和shell的屬性
- 根據(jù)/etc/fstab提供的掛載信息, 進(jìn)行文件系統(tǒng)的掛載
- busybox 會從 /etc/inittab中讀取sysinit并執(zhí)行, 這里sysinit指向了/etc/init.d/rcS
- /etc/init.d/rcS 中 ,mdev -s 這條命令很重要, 它會掃描/sys目錄,查找字符設(shè)備和塊設(shè)備,并在/dev下mknod
dev目錄:
# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/dev [1:17:36]
$ sudo mknod console c 5 1
這一步很重要, 沒有console這個(gè)文件, 用戶態(tài)的輸出沒法打印到串口上
lib目錄:拷貝lib庫,支持動態(tài)編譯的應(yīng)用程序運(yùn)行:
# bryant @ ubuntu in ~/Downloads/busybox-1.33.1/_install/lib [1:18:43]
$ cp /usr/aarch64-linux-gnu/lib/*.so* -a .
編譯內(nèi)核
配置內(nèi)核
linux內(nèi)核源碼可以在github上直接下載。
根據(jù)arch/arm64/configs/defconfig 文件生成.config
make defconfig ARCH=arm64
將下面的配置加入.config文件中
CONFIG_DEBUG_INFO=y
CONFIG_INITRAMFS_SOURCE="./root"
CONFIG_INITRAMFS_ROOT_UID=0
CONFIG_INITRAMFS_ROOT_GID=0
CONFIG_DEBUG_INFO是為了方便調(diào)試
CONFIG_INITRAMFS_SOURCE是指定kernel ramdisk的位置,這樣指定之后ramdisk會直接被編譯到kernel 鏡像中。
我們將之前制作好的根文件系統(tǒng)cp到root目錄下:
# bryant @ ubuntu in ~/Downloads/linux-arm64 on git:main x [1:26:56]
$ cp -r ../busybox-1.33.1/_install root
執(zhí)行編譯
make ARCH=arm64 Image -j8 CROSS_COMPILE=aarch64-linux-gnu-
這里指定target為Image 會只編譯kernel, 不會編譯modules, 這樣會增加編譯速度
啟動qemu
下載qemu
需要注意的,qemu最好源碼編譯, 用apt-get直接安裝的qemu可能版本過低,導(dǎo)致無法啟動arm64內(nèi)核。筆者是使用4.2.1版本的qemu
apt-get install build-essential zlib1g-dev pkg-config libglib2.0-dev binutils-dev libboost-all-dev autoconf libtool libssl-dev libpixman-1-dev libpython-dev python-pip python-capstone virtualenv
wget https://download.qemu.org/qemu-4.2.1.tar.xz
tar xvJf qemu-4.2.1.tar.xz
cd qemu-4.2.1
./configure --target-list=x86_64-softmmu,x86_64-linux-user,arm-softmmu,arm-linux-user,aarch64-softmmu,aarch64-linux-user --enable-kvm
make
sudo make install
編譯完成之后,qemu在 /usr/local/bin目錄下
$ /usr/local/bin/qemu-system-aarch64 --version
QEMU emulator version 4.2.1
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers
啟動linux內(nèi)核
/usr/local/bin/qemu-system-aarch64 -m 512M -smp 4 -cpu cortex-a57 -machine virt -kernel arch/arm64/boot/Image -append "rdinit=/linuxrc nokaslr console=ttyAMA0 loglevel=8" -nographic -s
這里對于參數(shù)做一些解釋:
-m 512M
?內(nèi)存為512M
-smp 4
?4核
-cpu cortex-a57
cpu 為cortex-a57
-kernel
?kernel鏡像文件
-append
傳給kernel 的cmdline參數(shù)。其中rdinit指定了init進(jìn)程;nokaslr 禁止內(nèi)核起始地址隨機(jī)化,這個(gè)很重要, 否則GDB調(diào)試可能有問題;console=ttyAMA0指定了串口,沒有這一步就看不到linux的輸出;
-nographic
禁止圖形輸出
-s
監(jiān)聽gdb端口, gdb程序可以通過1234這個(gè)端口連上來。
這里說明一下console=ttyAMA0是怎么生效的。
查看linux源碼可知ttyAMA0對應(yīng)的是AMBA_PL011
這個(gè)驅(qū)動:
config SERIAL_AMBA_PL011_CONSOLE
bool "Support for console on AMBA serial port"
depends on SERIAL_AMBA_PL011=y
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
help
Say Y here if you wish to use an AMBA PrimeCell UART as the system
console (the system console is the device which receives all kernel
messages and warnings and which allows logins in single user mode).
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
"console=ttyAMA0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
AMBA_PL011是arm的一個(gè)標(biāo)準(zhǔn)串口設(shè)備, qemu 的輸出就是模擬的這個(gè)串口。
在qemu的源碼文件中,也可以看到PL011的相關(guān)文件:
# bryant @ ubuntu in ~/Downloads/qemu-4.2.1 [1:46:54]
$ find . -name "*pl011*"
./hw/char/pl011.c
成功啟動Linux后, 串口打印如下:
[ 3.401567] usbcore: registered new interface driver usbhid
[ 3.404445] usbhid: USB HID core driver
[ 3.425030] NET: Registered protocol family 17
[ 3.429743] 9pnet: Installing 9P2000 support
[ 3.435439] Key type dns_resolver registered
[ 3.440299] registered taskstats version 1
[ 3.443685] Loading compiled-in X.509 certificates
[ 3.461041] input: gpio-keys as /devices/platform/gpio-keys/input/input0
[ 3.473163] ALSA device list:
[ 3.474432] No soundcards found.
[ 3.485283] uart-pl011 9000000.pl011: no DMA platform data
[ 3.541376] Freeing unused kernel memory: 10752K
[ 3.545897] Run /linuxrc as init process
[ 3.548390] with arguments:
[ 3.550279] /linuxrc
[ 3.551073] nokaslr
[ 3.552216] with environment:
[ 3.554396] HOME=/
[ 3.555898] TERM=linux
[ 3.985835] 9pnet_virtio: no channels available for device kmod_mount
mount: mounting kmod_mount on /mnt failed: No such file or directory
/etc/init.d/rcS: line 8: can't create /proc/sys/kernel/hotplug: nonexistent directory
Please press Enter to activate this console.
[root@bryant ]#
[root@bryant ]#
VSCode+GDB
vscode中集成了GDB功能,我們可以用它來圖形化的調(diào)試linux kernel
首先我們添加vscode的gdb配置文件(.vscode/launch.json):
{
// 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",
"program": "${workspaceFolder}/vmlinux",
"cwd": "${workspaceFolder}",
"MIMode": "gdb",
"miDebuggerPath":"/usr/bin/gdb-multiarch",
"miDebuggerServerAddress": "localhost:1234"
}
]
}
這里對幾個(gè)重點(diǎn)參數(shù)做一些說明:
program
: 調(diào)試的符號文件
miDebuggerPath
:gdb的路徑, 這里需要注意的是,由于我們是arm64內(nèi)核,因此需要用gdb-multiarch來進(jìn)行調(diào)試
miDebuggerServerAddress
:對端地址,qemu會默認(rèn)使用1234這個(gè)端口
配置完成之后,可以直接啟動GDB, 連接上linux kernel
在vscode中,可以設(shè)置斷點(diǎn),進(jìn)行單步調(diào)試
文章來源地址http://www.zghlxwxcb.cn/news/detail-474441.html
到了這里,關(guān)于VSCode+GDB+Qemu調(diào)試ARM64 linux內(nèi)核的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!