调试系统:
系统:Fedora 29
内核:5.0.6-200.fc29.x86_64
调试目标系统:
系统:CentOS 7.6
内核:3.10.0-957.10.1.el7.x86_64
在操作以下步骤之前,先用命令行方式启动虚拟机,参见我的另一篇文章:
https://blog.csdn.net/lonely_geek/article/details/89160627
在命令行后面加入 -s -S 启动gdb远程调试
1、下载并编译内核源码
在虚拟机上执行以下命令:
yumdownloader --source kernel-$(uname -r) //下载当前内核对应的源码包
rpm -ivh kernel-3.10.0-957.10.1.el7.src.rpm
rpmbuild -bp ~/rpmbuild/SPECS/kernel.spec
cd ~/rpmbuild/BUILD/kernel-3.10.0-957.10.1.el7/linux-3.10.0-957.10.1.el7.x86_64/
make -j8 vmlinux
2、复制带调试信息的vmlinux文件和整个源代码到调试机:
scp vmlinux czh@192.168.122.1:~
cd ..
make clean
tar cvzf kernel.tar.gz linux-3.10.0-957.10.1.el7.x86_64/
scp kernel.tar.gz czh@192.168.122.1:~
[注:]复制的vmlinux文件在内核源码根目录下,大概有几百MB,带调试信息的。我们最终生成的内核(安装到boot下的,只有几MB,是不带调试信息的)
3、在调试机上将源代码解压,并将vmlinux移动到源代码根目录下
4、修改内核引导参数:
vi /etc/default/grub,
修改CMDLINE这一行,追加一个参数:nokaslr
GRUB_CMDLINE_LINUX="crashkernel=256M rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb nokaslr"
[注:]nokaslr用于关闭内核起始地址随机化功能,如果不关闭,调试时会报类似错误:Cannot access memory at address 0xffffffff82819ad0
5、更新grub后重启虚拟机系统
grub2-mkconfig --output /boot/grub2/grub.cfg
reboot
6、调试机上执行过程如下:
[czh@localhost ~]$ cd kernel/
[czh@localhost kernel]$ gdb
GNU gdb (GDB) Fedora 8.2-6.fc29
Copyright (C) 2018 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-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://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...done.
(gdb) target remote :1234
Remote debugging using :1234
native_safe_halt () at ./arch/x86/include/asm/irqflags.h:54
54 }
(gdb) b vfs_read
Breakpoint 1 at 0xffffffff812414e0: file fs/read_write.c, line 451.
(gdb) c
Continuing.
[Switching to Thread 19]
Thread 19 hit Breakpoint 1, vfs_read (file=file@entry=0xffff880035434600, buf=buf@entry=0x7f40c4e1cb80 "\b", count=count@entry=272, pos=pos@entry=0xffff88022dff7f18)
at fs/read_write.c:451
451 {
(gdb) list
446 }
447
448 EXPORT_SYMBOL(do_sync_read);
449
450 ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
451 {
452 ssize_t ret;
453
454 if (!(file->f_mode & FMODE_READ))
455 return -EBADF;
(gdb) c
Continuing.
Thread 19 hit Breakpoint 1, vfs_read (file=file@entry=0xffff880035434600, buf=buf@entry=0x7f40c4e1cb80 "\b", count=count@entry=272, pos=pos@entry=0xffff88022dff7f18)
at fs/read_write.c:451
451 {
7、其他事项
1)gdb搜索源代码路径可以自己修改,利用下面一些命令即可:
directory path-list:将一个或者多个源代码搜索目录加入到当前源码搜索目录列表的前面,目录之间使用空格间隔。
directory:不带参数的directory将源码搜索目录恢复为默认值。
set directories path-list:将源码目录设置为path-list,但是会补上默认目录。
show directories:显示源码搜索目录列表。
2) 调试内核模块:内核模块并非集成在内核中,所以先要提前加载模块符号,让gdb找到相应的地址:
add-symbol-file xxx.ko 0x+地址 (需要写成0x开头)
(对应模块的.text起始地址,可以从/sys/module/xxx/sections/.text获取)
3)调试64位内核可能会出现有些函数无法被hit,例如b start_kernel,重启后并未断在此处。解决方法参考:https://bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/901944
使用hard break即可,例如:hb start_kernel
原文:-----------------------------------------------------------------------------------------------------
More details:
- It works if I use hbreak (GDB hardware-assisted breakpoints) instead of break for the very first breakpoint.
- After this first breakpoint, normal “break” breakpoints work fine, too.
- Accoording to http://chemnitzer.linux-tage.de/2012/vortraege/folien/1061-VirtualDebugging.pdf slide 18 this might be due to GDB not properly dealing with protocol changes. In this case, this is a GDB bug/issue, not a qemu-kvm one.