首页 > 系统相关 >Linux内核开发环境-使用GDB调试内核代码

Linux内核开发环境-使用GDB调试内核代码

时间:2024-09-15 12:52:10浏览次数:13  
标签:Linux 5.10 gdb GDB 内核 linux HOME 调试

建议点击这里查看个人主页上的最新原文

点击这里在哔哩哔哩bilibili在线观看配套的教学视频

点击这里在哔哩哔哩bilibili在线观看配套的加餐视频(就是一些补充)

点击跳转到内核课程所有目录

下面介绍Linux内核编译环境和测试环境的搭建过程,当然我也为各位朋友准备好了已经安装好的虚拟机镜像,只需下载运行即可。

点击这里从百度网盘下载对应平台的虚拟机镜像x86_64(也就是你平时用来安装windows系统的电脑,或者2020年前的苹果电脑)选择ubuntu-x64_64.ziparm64(2020年末之后的苹果电脑)选择ubuntu-aarch64.zip。虚拟机运行后,登录界面的密码是1

我刚开始是做用户态开发的,习惯了利用gdb调试来理解那些写得不好的用户态代码,尤其是公司内部一些不开源的比狗屎还难看的用户态代码(当然其中也包括我自己写的狗屎一样的代码)。

转方向做了Linux内核开发后,也尝试用qemu+gdb来调试内核代码。

要特别说明的是,内核的大部分代码是很优美的,并不需要太依赖qemu+gdb这一调试手段,更建议通过阅读代码来理解。但某些写得不好的内核模块如果利用qemu+gdb将能使我们更快的熟悉代码。

这里只介绍x86_64下的qemu+gdb调试,其他cpu架构以此类推,只需要做些小改动。

如果是其他cpu架构,要安装:

sudo apt install gdb-multiarch -y

编译选项和补丁

首先确保修改以下配置:

CONFIG_DEBUG_SECTION_MISMATCH=y # 防止内联
CONFIG_DEBUG_INFO=y # 调试信息
CONFIG_DEBUG_KERNEL=y # 调试信息
CONFIG_GDB_SCRIPTS=y # gdb python
DEBUG_INFO_REDUCED=n # 关闭
CONFIG_FRAME_POINTER=y # Makefile 中选择GCC编译选项
CONFIG_RANDOMIZE_BASE = n # 关闭地址随机化

可以使用我常用的x86_64的内核配置文件

gcc的编译选项O1优化等级不需要修改就可以编译通过。O0优化等级无法编译(尝试CONFIG_JUMP_LABEL=n还是不行),要修改汇编代码,有兴趣的朋友可以和我一直尝试。Og优化等级经过修改可以编译通过,x86_64合入目录courses/kernel/src/x86_64对应版本的补丁。建议使用Og优化等级编译,既能满足gdb调试需求,也能尽量少的修改代码。

QEMU命令选项

qemu启动虚拟机时,要添加以下几个选项:

-append "nokaslr ..." # 防止地址随机化,编译内核时关闭配置 CONFIG_RANDOMIZE_BASE
-S # 挂起 gdbserver
-gdb tcp::5555 # 端口5555, 使用 -s 选项表示用默认的端口1234
-s # 相当于 -gdb tcp::1234 默认端口1234,不建议用,最好指定端口

完整的启动命令查看制作好的Ubuntu虚拟机镜像(从百度网盘中下载的)中的${HOME}/qemu-kernel/start.sh脚本。

GDB命令

启动GDB:

gdb build/vmlinux

如果是其他架构:

gdb --tui build/vmlinux # --tui: Use a terminal user interface.
(gdb) set architecture aarch64

进入GDB界面后:

(gdb) target remote:5555 # 对应qemu命令中的-gdb tcp::5555
(gdb) b func_name # 普通断点
(gdb) hb func_name # 硬件断点,有些函数普通断点不会停下, 如: nfs4_atomic_open,降低优化等级后没这个问题

gdb命令的用法和用户态程序的调试大同小异。

GDB辅助调试功能

使用内核提供的GDB辅助调试功能可以更方便的调试内核(如打印断点处的进程名和进程id等)。

内核最新版本(2024.04)使用以下命令开启GDB辅助调试功能,注意最新版本编译出的脚本无法调试4.19和5.10的代码:

echo "set auto-load safe-path /" > ~/.gdbinit # 设置自动加载共享库文件的安全路径
echo "source ${HOME}/.gdb-linux/vmlinux-gdb.py" >> ~/.gdbinit
make O=build scripts_gdb # 在内核仓库目录下执行
rm -rf ${HOME}/.gdb-linux/
mkdir ${HOME}/.gdb-linux/
cp build/scripts/gdb/* ${HOME}/.gdb-linux/ -rf # 在内核仓库目录下执行
cp scripts/gdb/vmlinux-gdb.py ${HOME}/.gdb-linux/ # 在内核仓库目录下执行
sed -i '/sys.path.insert/s/^/# /' ${HOME}/.gdb-linux/vmlinux-gdb.py # 将sys.path.insert所在的行注释掉
sed -i '/sys.path.insert/a\sys.path.insert(0, "'${HOME}'/.gdb-linux")' ${HOME}/.gdb-linux/vmlinux-gdb.py # 插入 sys.path.insert(0, "${HOME}/.gdb-linux")

内核5.10使用以下命令开启GDB辅助调试功能,也可以调试内核4.19代码,但无法调试内核最新的代码:

echo "set auto-load safe-path /" > ~/.gdbinit # 设置自动加载共享库文件的安全路径
echo "source ${HOME}/.gdb-linux-5.10/vmlinux-gdb.py" >> ~/.gdbinit
make O=build scripts_gdb # 在5.10内核仓库目录下执行
rm -rf ${HOME}/.gdb-linux-5.10/
mkdir ${HOME}/.gdb-linux-5.10/
cp build/scripts/gdb/* ${HOME}/.gdb-linux-5.10/ -rf # 在5.10内核仓库目录下执行
cp scripts/gdb/vmlinux-gdb.py ${HOME}/.gdb-linux-5.10/ # 在5.10内核仓库目录下执行
sed -i '/sys.path.insert/s/^/# /' ${HOME}/.gdb-linux-5.10/vmlinux-gdb.py # 将sys.path.insert所在的行注释掉
sed -i '/sys.path.insert/a\sys.path.insert(0, "'${HOME}'/.gdb-linux-5.10")' ${HOME}/.gdb-linux-5.10/vmlinux-gdb.py # 插入 sys.path.insert(0, "${HOME}/.gdb-linux-5.10")

重新启动GDB就可以使用GDB辅助调试功能:

(gdb) apropos lx # 查看有哪些命令
(gdb) p $lx_current().pid # 打印断点所在进程的进程id
(gdb) p $lx_current().comm # 打印断点所在进程的进程名

GDB打印结构体偏移

结构体定义有时候加了很多宏判断,再考虑到内存对齐之类的因素,通过看代码很难确定结构体中某一个成员的偏移大小,使用gdb来打印就很直观。

如结构体struct cifsFileInfo:

struct cifsFileInfo {
    struct list_head tlist;
    ...
    struct tcon_link *tlink;
    ...
    char *symlink_target;
};

想要确定tlink的偏移,可以使用以下命令:

gdb ./cifs.ko # ko文件或vmlinux
(gdb) p &((struct cifsFileInfo *)0)->tlink

(struct cifsFileInfo *)0: 这是将整数值 0 强制类型转换为指向 struct cifsFileInfo 类型的指针。这实际上是创建一个指向虚拟内存地址 0 的指针,该地址通常是无效的。这是一个计算偏移量的技巧,因为偏移量的计算不依赖于结构体的实际实例。

(0)->tlink: 指向虚拟内存地址 0 的指针的成员tlink

&(0)->tlink: tlink的地址,也就是偏移量。

ko模块代码调试

使用gdb vmlinux启动gdb后,如果调用到ko模块里的代码,这时候就不能直接对ko模块的代码进行打断点之类的操作,因为找不到对应的符号。

这时就要把符号加入进来。首先,查看被调试的qemu虚拟机中的各个段地址:

cd /sys/module/ext4/sections/ # ext4 为模块名
cat .text .data .bss # 输出各个段地址

在gdb窗口中加载ko文件:

add-symbol-file <ko文件位置> <text段地址> -s .data <data段地址> -s .bss <bss段地址>

这时就能开心的对ko模块中的代码进行打断点之类的操作了。

标签:Linux,5.10,gdb,GDB,内核,linux,HOME,调试
From: https://blog.csdn.net/chenxiaosongcsdn/article/details/142282728

相关文章

  • 国产RAID卡2230-10i windows&Linux操作系统安装指导
    环境准备:1.准备2个U盘。一个刻录系统,一个装载驱动2.需保持CSM为UEFI状态和PCIEDEVICESLIST 下2230-10i的卡为UEFI状态,如图:环境排查:由于......
  • Linux下使用pipe进行父子进程间通信
    引入之前我们介绍了多进程以及创建进程的函数fork,下面我们将继续深入,讨论一下多进程间的通信问题;pipe管道谈论多进程通信,就离不开pipe(管道),这是一个系统调用,用于在UNIX和类UNIX系统(如Linux)上创建一个管道(pipe),实现进程间通信。它创建了一个双向的通信通道,允许一个进程向另一......
  • 4.linux重定向和管道
    目录 一.重定向1.FD2.重定向案例><2.1输出>2.2输入<3.扩展二.管道1.管道|1.1进程管道Piping1.2tee管道2.参数传递Xargs 一.重定向 #touchtime#date>time.txt//>将本身输出到屏幕的东西给他弄到time文件中 1.FD-----标准输入、标准输......
  • linux 操作系统下的compress命令介绍和使用案例
    linux操作系统下的compress命令介绍和使用案例compress命令是Linux系统中用于文件压缩的一个工具,主要使用Lempel-Ziv-Welch(LZW)算法进行数据压缩。压缩后,文件的扩展名将变为“.Z”。虽然compress命令在历史上有其重要性,但在现代Linux系统中,它已经被更高效的压缩工具如gzip......
  • linux 操作系统下cp命令介绍及案例应用
    linux操作系统下cp命令介绍及案例应用cp命令是Linux操作系统中用于复制文件和目录的基本命令。它的功能强大,适用于各种文件管理任务cp命令概述基本语法:bashcp[options]<source><destination>功能:复制单个文件或多个文件到指定位置。递归复制目录及其内容。选项可......
  • Linux内存管理方式
    Linux内存管理涉及到多个方面,包括物理内存的分配和回收、虚拟内存的管理、页面置换、内存保护等。以下是Linux内存管理的主要方式和机制:1.虚拟内存(VirtualMemory)虚拟地址空间:每个进程拥有自己的虚拟地址空间,虚拟地址空间与物理内存是分开的。进程在运行时使用虚拟地......
  • 1Panel:一个现代化、开源的 Linux 服务器运维管理面板
    前言之前有小伙伴问:Linux服务器运维管理除了宝塔,还有其他值得推荐的管理软件吗?,今天大姚给大家分享一个现代化、开源的Linux服务器运维管理面板:1Panel。项目介绍1Panel是新一代的Linux服务器运维管理面板,旨在通过现代化的Web界面帮助用户轻松管理Linux服务器。该项目是开......
  • 1Panel:一个现代化、开源的 Linux 服务器运维管理面板
    前言之前有小伙伴问:Linux服务器运维管理除了宝塔,还有其他值得推荐的管理软件吗?,今天大姚给大家分享一个现代化、开源的Linux服务器运维管理面板:1Panel。项目介绍1Panel是新一代的Linux服务器运维管理面板,旨在通过现代化的Web界面帮助用户轻松管理Linux服务器。该项目......
  • 3.linux进程管理
    目录一.进程管理1.进程概念2.进程生命周期和状态3.进程管理process3.1ps-静态查看进程3.2 top-动态查看进程3.3.使用信号控制进程3.4nice-优先级二.作业控制jobs三.虚拟文件系统proc四.线程(可看可不看)1.状态2.调度算法3.通信方式4.线程和进程的区别5.线......
  • USB总线-Linux内核USB3.0 Hub驱动分析(十四)
    1.概述USBHub提供了连接USB主机和USB设备的电气接口。USBHub拥有一个上行口,至少一个下行口,上行口连接上一级的Hub的下行口或者USB主机,连接主机的为RootHub,下行口连接下一级Hub的上行口或者USB设备。经过Hub的扩展,一个USB主机可以和多个USB设备通信。USBHub有如下特性:良好的......