1、首先关于kernel的一些总结:
内核在make modules的时候,会生成模块的可执行文件,make modules_install会把这写可执行文件都copy到/lib/modules/X.Y.Z目录下。该目录下都是模块,还有一个build目录,是源码目录的链接。
再总结一些kgdb调试的内容:
2、目标机:
目标机进入内核调试状态有两种方式:
方式一:在grub引导时就加入启动参数
kgdboc=ttyS0,115200 kgdbwait
echo g>/proc/sysrq-trigger
此时,调试机进入假死状态,等待远程gdb的链接。
#insmod hello.ko(/root/mod1/)
宿主机:
#stty speed
#gdb -q vmlinux(vmlinux是一个二进制文件)
(gdb)set debug remote 1(显示调试过程中跟gdb通信的数据包)
(gdb)target remote /dev/ttyS0
(gdb) b kernel/module.c:3042(在模块的初始化函数处设置断点)
(gdb)c(此时客户端从假死状态中退出)
此时目标端运行insmod之后,会命中断点,接下来就能进行调试工作。
如果此时想查看模块的加载信息,可以自定义gdb的宏lsmod。然后对该宏进行加载。
(gdb)source lsmod
(gdb)lsmod
在linux系统中,模块的初始地址会保存在结构体struct module所构成的链表中。
我们首先获取当前模块的module结构体的起始地址。
(gdb)set $m=(struct module *)0xF8137000
(gdb)p $m->module_core
(gdb)p $m->module_init
此时就可以加载模块的符号信息。
(gdb)add-symbol-file /root/mod1/hello.ko module_core .init.text module_init
加载完成之后,就可以在模块的源码中设置断点了,注意:此时设置断点的方式必须为硬件断点。
(gdb)hbreak hello_init
问题:为什么在源码设置断点,调试的vmlinux会命中呢?
vmlinux是源码的符号表,将源码的符号(函数名等)跟地址对应起来。这样,gdb在设置断点的时候,在符号(函数名,变量等)处设置断点就相当于在vmlinux中的地址处设置断点了。
3、补充
调试模块的时候,目标机和主机都需要有模块的源码,而且目录结构要一样,不然,在运行gdb的主机(宿主机)上找不到相应的内容。