当前位置:   article > 正文

Linux内核qemu&gdb调试记录-20230509_qemu 卸载

qemu 卸载

一、编译Linux内核调试源码

编译方法如下:

git clone https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.179.tar.xz
tar -xvzf linux-5.10.179.tar.gz
cd linux-5.10.179
make menuconfig
  • 1
  • 2
  • 3
  • 4

在内核编译选项中,开启如下"Compile the kernel with debug info",在配置菜单中,启用内核debug,关闭地址随机化,不然断点处无法停止。

Kernel hacking --->
  Compile-time checks and compiler options --->
    [ ] Compile the kernel with debug info
    
Processor type and features ---->
    [] Randomize the address of the kernel image (KASLR)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

以上配置完成后会在当前目录生成 .config 文件,我们可以使用 grep 进行验证:

grep CONFIG_DEBUG_INFO .config
CONFIG_DEBUG_INFO=y
  • 1
  • 2

编译内核

make -j4
  • 1

编译完成后,会在当前目录下生成vmlinux,这个在 gdb 的时候需要加载,用于读取 symbol 符号信息,包含了所有调试信息,所以比较大。

压缩后的镜像文件为bzImage, 在arch/arm64/boot目录下。

pwd
/home/liujianguo/DebugLinuxKernal/linux-5.10.174/arch/arm64/boot

ls
Image  Image.gz  install.sh  Makefile
  • 1
  • 2
  • 3
  • 4
  • 5

二、编译busybox

Linux系统启动阶段,boot loader加载完内核文件vmlinuz后,内核紧接着需要挂载磁盘根文件系统,但如果此时内核没有相应驱动,无法识别磁盘,就需要先加载驱动。

而驱动又位于/lib/modules,得挂载根文件系统才能读取,这就陷入了一个两难境地,系统无法顺利启动。

于是有了initramfs根文件系统,其中包含必要的设备驱动和工具,bootloader加载initramfs到内存中,内核会将其挂载到根目录/,然后运行/init脚本,挂载真正的磁盘根文件系统。

这里借助BusyBox构建极简initramfs,提供基本的用户态可执行程序。

可以从busybox官网地址下载最新版本,或者直接使用wget下载我使用的版本。

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
  • 1
  • 2
  • 3
  • 4

在编译busybox之前,我们需要对其进行设置,执行make menuconfig,如下

 Settings  --->
            [*] Build BusyBox as a static binary (no shared libs) 
  • 1
  • 2

这里一定要选择静态编译,编译好的可执行文件busybox不依赖动态链接库,可以独立运行,方便构建initramfs。

之后选择Exit退出,到这里我们就可以编译busybox了,执行下面的命令

make -j 8

# 安装完成后生成的相关文件会在 _install 目录下
make install
  • 1
  • 2
  • 3
  • 4

三、构建initramfs根文件系统

1. 创建initramfs

[root@localhost temp]# ls
busybox-1.29.0  busybox-1.29.0.tar.bz2
[root@localhost temp]# mkdir initramfs
[root@localhost temp]# cd initramfs
[root@localhost initramfs]# cp ../busybox-1.29.0/_install/* -rf ./
[root@localhost initramfs]# mkdir dev proc sys
[root@localhost initramfs]# sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/
[root@localhost initramfs]# rm -f linuxrc
[root@localhost initramfs]# vim init
[root@localhost initramfs]# chmod a+x init
[root@localhost initramfs]# ls
bin  dev  init  proc  sbin  sys  usr
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

其中init的内容如下

#!/bin/busybox sh
echo "{==DBG==} INIT SCRIPT"
mount -t proc none /proc
mount -t sysfs none /sys

echo -e "{==DBG==} Boot took $(cut -d' ' -f1 /proc/uptime) seconds"
exec /sbin/init
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2. 打包initramfs

find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz
[root@localhost initramfs]# ls ../
busybox-1.29.0  busybox-1.29.0.tar.bz2  initramfs  initramfs.cpio.gz
  • 1
  • 2
  • 3

四、安装qemu(编译安装)

1. 编译安装过程

在安装Qemu之前,先安装必要的包( 安装包的过程中,遇到哪个包安装出错,就把哪个包移除再安装其他的包)。

sudo apt-get update
sudo apt-get install gcc make perl ninja-build git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev libaio-dev libbluetooth-dev libbrlapi-dev libbz2-dev libcap-dev libcap-ng-dev libcurl4-gnutls-dev libgtk-3-dev libibverbs-dev libjpeg8-dev libncurses5-dev libnuma-dev librbd-dev librdmacm-dev libsasl2-dev libsdl1.2-dev libseccomp-dev libsnappy-dev libssh2-1-dev libvde-dev libvdeplug-dev libxen-dev liblzo2-dev valgrind xfslibs-dev libnfs-dev libiscsi-dev uml-utilities net-tools bridge-utils
sudo apt install python3-pip
sudo pip3 install meson
  • 1
  • 2
  • 3
  • 4

下载Qemu:

wget https://download.qemu.org/qemu-8.0.0.tar.xz
  • 1

编译Qemu:

tar -xvf qemu-6.1.1.tar.xz
cd qemu-6.1.1
sudo ./configure
sudo make -j 4
  • 1
  • 2
  • 3
  • 4

安装Qemu(可选):

sudo make install
  • 1

检查Qemu版本:

$ cd ..
$ qemu-system-arm -version
QEMU emulator version 6.1.1
Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers
  • 1
  • 2
  • 3
  • 4

**注意:**编译后,在qemu-8.0.0/build目录下有相应的执行文件,可以不用使用make install安装。使用方法如下:

/home/liujianguo/DebugLinuxKernal/qemu-8.0.0/build/qemu-system-aarch64 \
        -machine virt \
        -m 8G \
        -smp 24 \
        -cpu cortex-a57 \
        -kernel ./arch/arm64/boot/Image \
        -initrd ../initramfs.cpio.gz \
        -append "nokaslr console=ttyAMA0 loglevel=8" \
        -nographic \
        -s -S
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

2. 安装多个版本pyton方法

安装过程中,可能出现pyton版本过低的问题,可以通过以下命令查看当前安装python版本

python3.6 --version
Python 3.6.9

python3.7 --version
Python 3.7.5
  • 1
  • 2
  • 3
  • 4
  • 5

输入以下命令,将Python3.7设置为默认的Python版本:

sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1
sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 2
sudo update-alternatives --config python3
  • 1
  • 2
  • 3

执行最后一个命令后,会出现以下提示:

sudo update-alternatives --config python3
There are 2 choices for the alternative python3 (providing /usr/bin/python3).

  Selection    Path                Priority   Status
------------------------------------------------------------
  0            /usr/bin/python3.7   2         auto mode
  1            /usr/bin/python3.6   1         manual mode
* 2            /usr/bin/python3.7   2         manual mode

Press <enter> to keep the current choice[*], or type selection number: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

输入相应数字就可以选择相应版本。

3. 卸载编译安装的qemu方法

qemu卸载根据安装方式的不同也会有响应的卸载方式:(1)源码编译安装需要手动卸载;(2)ubutnu pakage安装需要命令卸载

(1) 源码编译安装的qemu需要手动卸载:

源码安装后,文件的位置:

可执行文件默认放在/usr/local/bin

库文件默认存放在/usr/local/libexec

配置文件默认存放在/usr/local/etc

共享文件默认存放在/usr/local/share

卸载源码只需将上面四个目录中相关文件或者目录删除

rm -rf /usr/local/bin/qemu-*
rm -rf /usr/local/libexec/qemu-bridge-helper
rm -rf /usr/local/etc/qemu
rm -rf /usr/local/share/qemu
  • 1
  • 2
  • 3
  • 4

(2) pakage安装方式需命令卸载

删除包和相关依赖

sudo apt-get remove --auto-remove qemu-system-x86
  • 1

删除配置文件和相关的数据文件

sudo apt-get purge --auto-remove qemu-system-x86
  • 1

五、安装qemu(apt安装)

1. 安装方法

apt install qemu qemu-utils qemu-kvm virt-manager libvirt-daemon-system libvirt-clients bridge-utils
  • 1

2. qemu的一些疑惑

(1) qemu-aarch64和qemu-system-aarch64区别?

qemu-aarch64qemu-system-aarch64其实是同一个软件的两种不同命令,其中qemu-aarch64是一种简化的命令,通常用于启动默认的ARM 64位架构,而qemu-system-aarch64则是一个更全面的命令,可以更加灵活地配置各种参数。使用qemu-system-aarch64命令可以更好地控制模拟器的行为,可以配置更多的设备,比如网卡、硬盘、CD-ROM等,并且可以定制化模拟器的启动参数。因此,在一些需要复杂配置的场景下,使用qemu-system-aarch64可能会更加方便。

(2) console=ttyAMA0和console=ttyS0区别?

console=ttyAMA0console=ttyS0都是指定Linux内核将控制台输出重定向到特定的串口设备。

ttyAMA0是ARM体系结构中某些板卡默认的串口设备,通常在使用UART接口调试时使用。

ttyS0是标准的串口设备,通常在PC中使用,并且也适用于其他一些体系结构的设备。在使用虚拟机调试时,通常会使用ttyS0作为控制台输出设备。

六、安装GDB

1. 安装过程

wget https://ftp.gnu.org/gnu/gdb/gdb-10.1.tar.gz
tar -xzvf gdb-10.1.tar.gz
cd  gdb-10.1
./configure
# 必需要安装这两个库
sudo apt-get install texinfo
sudo apt-get install build-essential
make -j 8
sudo make install
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2. GDB常见命令

以下是一些 GDB 常用的操作快捷键:

  • run (简写 r):运行程序,可以带参数

  • break (简写 b):设置断点

  • continue (简写 c):继续运行程序直到遇到下一个断点或者程序结束

  • next (简写 n):单步执行一行源代码,如果这一行代码中有函数调用,则不会进入函数体内部

  • step (简写 s):单步执行一行源代码,如果这一行代码中有函数调用,则会进入函数体内部

  • print (简写 p):打印变量的值或者表达式的值

  • info:打印关于程序状态的信息

    • info break:打印所有断点的信息
    • info registers:打印寄存器的值
    • info locals:打印当前函数中的局部变量
  • backtrace (简写 bt):打印函数调用栈

  • quit (简写 q):退出 GDB

  • 断开GDB连接快捷键:Ctrl+D

这只是一些常用的操作快捷键,GDB 还有很多其它的命令和选项,可以通过输入 help 或者 help <command> 来查看帮助文档。

七、QEMU&GDB启动调试内核

1. arm64 Linux内核调试启动方法

arm64 Linux内核调试启动方法如下:

/home/liujianguo/DebugLinuxKernal/qemu-8.0.0/build/qemu-system-aarch64 \
        -machine virt \
        -m 8G \
        -smp 24 \
        -cpu cortex-a57 \
        -kernel ./arch/arm64/boot/Image \
        -initrd ../initramfs.cpio.gz \
        -append "nokaslr console=ttyAMA0 loglevel=8" \
        -nographic \
        -s -S
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

2. x86 Linux内核调试启动方法

x86 Linux内核调试启动方法如下:

qemu-system-x86_64 -kernel ./arch/x86/boot/bzImage -initrd ../initramfs.cpio.gz -append "nokaslr console=ttyS0" -s -S -nographic
  • 1

3. qemu参数命令介绍:

  • -kernel ./arch/x86/boot/bzImage:指定启用的内核镜像;
  • -initrd ../initramfs.cpio.gz:指定启动的内存文件系统;
  • -append "nokaslr console=ttyS0" :附加参数,其中 nokaslr 参数必须添加进来,防止内核起始地址随机化,这样会导致 gdb 断点不能命中;
  • -s :监听在 gdb 1234 端口;
  • -S :表示启动后就挂起,等待 gdb 连接;
  • -nographic:不启动图形界面,调试信息输出到终端与参数 console=ttyS0 组合使用;
  • 结束qemu仿真方法:先按Ctrl+a,松开后按x

4. 启动gdb调试

在另一个窗口中,输入gdb,即可开启调试。

gdb

GNU gdb (GDB) 10.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".

(gdb) file vmlinux
Reading symbols from vmlinux...

(gdb) target remote localhost:1234
Remote debugging using localhost:1234
warning: Can not parse XML target description; XML support was disabled at compile time
warning: Assuming long-mode change. [Remote 'g' packet reply is too long: PU]
0x000000000000fff0 in exception_stacks ()

(gdb) break start_kernel
Breakpoint 1 at 0xffffffff81fc6a95: file init/main.c, line 486.

(gdb) break  rest_init
Breakpoint 2 at 0xffffffff818aa1e1: file init/main.c, line 385.

(gdb) c
Continuing.

Breakpoint 1, start_kernel () at init/main.c:486
486             set_task_stack_end_magic(&init_task);
(gdb) c
Continuing.

Breakpoint 2, rest_init () at init/main.c:385
385     {
(gdb) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

在start_kernel 和 rest_init 打了两个断点, 两个断点都成功命中了。

八、使用vs code进行gdb调试

1. 插件需求

  • ms-vscode.cpptools
  • remote-ssh
  • gdb

2. 项目调式配置

在界面上打开:run->Add Configuration,在launch.json中编辑以下内容(注意此配置设置调试目标Linux架构为arm架构):

{
    "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",
            "setupCommands": [
            	{
                	"text": "set architecture arm",
                	"description": "Set target architecture to ARM"
                	"ignoreFailures": true
            	}
        	]
        }
    ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

3. 启动调试

在调试之前,需要启动qemu调试服务,使用F5快捷键就可以启动调试。

参考来源

  1. 利用QEMU+GDB搭建Linux内核调试环境
  2. Ubuntu20.04 上安装Qemu 6.1.1
  3. vscode + gdb 远程调试 linux 内核源码(附视频)
  4. Qemu安装之后如何卸载
  5. Chat gpt
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/239878
推荐阅读
相关标签
  

闽ICP备14008679号