2013/05/23

Linux Insert Module Error: Unknown symbol xxxxxxx


前幾天在幫 NAS 灌上 Virtualbox 時編譯 kernel module(DKMS) 時出錯,後來手動編譯,卻在 insmod 時 出現錯誤,dmesg 也出現下面這樣的錯誤訊息:

$ insmod vboxdrv/vboxdrv.ko
insmod: error inserting 'vboxdrv/vboxdrv.ko': -1 Invalid parameters
$ dmesg | tail
[84167.691738] vboxdrv: disagrees about version of symbol sched_setscheduler
[84167.698665] vboxdrv: Unknown symbol sched_setscheduler (err -22)
[84167.704799] vboxdrv: disagrees about version of symbol wake_up_process
[84167.711336] vboxdrv: Unknown symbol wake_up_process (err -22)
[84167.717174] vboxdrv: disagrees about version of symbol __free_pages
[84167.723506] vboxdrv: Unknown symbol __free_pages (err -22)

會出現這樣的錯誤,大概是因為我沒有原本 NAS 的 kernel source code and config,所以只能用 uname -r 找到一個差不多的版本,再參考其 header 編譯造成。但是該如何解這樣的問題呢?

首先確定每個 unknown symbol 的位址,以 sched_setscheduler 為例:

$ grep 'T sched_setscheduler$' /proc/kallsyms
ffffffff8105c250 T sched_setscheduler

接著準備 symbol address map,如下:

$ tee addrs.dat <%lt;EOF
SECTIONS
{
sched_setscheduler = 0xffffffff8105c250;
wake_up_process = 0xffffffff8105a400;
__free_pages = 0xffffffff81111de0;
}
EOF

這個格式應該很容易懂,大概就是 <unknown symbol> = <address> 這樣的格式。最後重新 link ko 用以下指令:

$ ld -r -o vboxdrv/vboxdrv-1.ko vboxdrv/vboxdrv.ko -R addrs.dat

打完收工。