如何调试Linux内核模块的init_module()调用?

jexiocij  于 2023-04-11  发布在  Linux
关注(0)|答案(3)|浏览(155)

我正在做Linux内核开发的第一步。我有一些代码生成一个.ko内核模块,我用insmod安装。我想有一种方法来调试安装模块时发生的事情,但我面临着一些困难。
1.我需要调试对init_module的调用。当我运行insmode时,是否会调用此函数?
1.我尝试使用insmod "/my/url/fil.ko" -m调试发生的情况,但每次我都得到错误-1 Unknown symbol in module,而在/cat/log/message中,我可以看到错误unknown parameter -m
1.你知道有没有一种方法可以用GDB进行调试?

liwlm1x9

liwlm1x91#

是的,init_module函数会在你使用insmod将它加载到内核时被调用。你可以添加一行printk,并在你插入模块时验证它是否被打印出来。
不能传递-m之类的参数来调试内核模块。
您只能使用MODULE_PARAMS传递要在您编写的内核模块中处理的参数。

wtzytmuj

wtzytmuj2#

QEMU + GDB单步调试module_init

在试用module_init之前,先调试内核模块QEMU + GDB的一般工作情况:如何使用QEMU调试Linux内核模块?
module_init更难,因为我们不知道内核模块将在哪里加载。
然后,这里有两个不理想但可用的技术来破解module_init

  • 找到模块加载地址,并在以后重用它。

模块加载位置在每次 Boot 后都是确定的,因此我们可以找到:

./readelf -s fops.ko | grep myinit

然后,将它们相加,并告诉GDB在该点中断。

  • 进入module_init调用。

在内核4.16上,第一次中断在:

do_init_module

然后步进,直到:

ret = fn();

然后进入该函数,就进入了module_init函数。
这个QEMU + Buildroot设置可以用来方便地测试这两种方法。

mwkjh3gx

mwkjh3gx3#

GDB本身不能捕获模块的init和exit函数上的断点,就像它可以捕获其他用于服务设备节点上的系统调用的函数一样(例如打开,阅读或写入设备)。我怀疑这与它们存储在进程地址空间的哪个部分有关,但我不确定。
使问题更加复杂的是,模块每次都是在随机地址上加载的,而不管nokaslr是什么,也不管它们是静态构建的还是动态插入内核的。(使用nokaslr时,内核的核心部分将始终加载到同一个地址空间,但模块不会)。因此,您不能简单地加载模块,在init符号的当前地址上设置断点,并重新加载模块。不过,有一个解决方案:
就像Ciro在他的答案的方法2中所说的那样,你需要在内核的do_init_module函数上设置一个断点,每次加载任何模块时都会调用该函数。由于它是我提到的核心内核代码的一部分,gdb将知道它的正确位置。从那里,而不是单步执行很多次(可能数百次,从我的尝试),按照我最近发现的这个webpost的说明:
https://sysprogs.com/VisualKernel/documentation/kernelsymbols/

相关问题