kernel module程式設計(十) 檢視錯誤

2021-08-25 12:38:48 字數 3613 閱讀 4997

本文也即《linux device drivers》,ldd3的第四章debuging techniques的讀書筆記之五,但我們不限於此內容。

開發中我們不能避免在執行驅動時引起系統fault,但fault並不意味就是panic,linux還是robust的,對於驅動,通常只引 起正在使用該驅動的程序死掉,kernel在任何乙個開啟裝置的程序死掉的時候會呼叫close開進行釋放。雖然如此,但是oops發生的時候,即使我們 解除安裝了核心模組程式但是系統仍可能不正常,通常需要重啟來恢復,這是在console會有一些資訊列印出來,可能通過他們來獲取程式bug問題。如果我們 的terminal不是系統的console,即無法顯示printk的內容,可以通過dmesg來嘗試。

例如無效的指標會產生oops訊息。我們可以在scull_write中加入來實驗一下:

*( int *) 0 =0 ; //產生乙個null pointer的錯誤。載入後,執行帶寫操作的使用者程式(我的使用者程式為test),在dmesg中有以下的報錯:

bug: unable to handle kernel null pointer dereference at 00000000

ip: :scull:scull_write+0x24/0x260

*pde = 2b2d3067 *pte = 00000000

oops: 0002 [#1] smp

modules linked in: scull vfat fat usb_storage fuse sco bridge stp bnep l2cap bluetooth sunrpc ip6t_reject nf_conntrack_ipv6 ip6table_filter ip6_tables ipv6 cpufreq_ondemand acpi_cpufreq dm_multipath kvm_intel kvm uinput snd_hda_intel snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss fglrx(p) snd_pcm snd_timer snd_page_alloc snd_hwdep snd ppdev e1000e i2c_i801 i2c_core soundcore serio_raw pcspkr dcdbas parport_pc itco_wdt ata_generic itco_vendor_support parport pata_acpi [last unloaded: microcode]

pid: 17913, comm: testtainted: p (2.6.27.5-117.fc10.i686 #1)

eip: 0060: eflags: 00010296 cpu: 0

eip is at scull_write +0x24/0x260 [scull ]

eax: 00000040 ebx: 00000400 ecx: 000005dc edx: b7f03000

esi: eb270540 edi: f8a3f376 ebp: f272ef74 esp: f272ef18

ds: 007b es: 007b fs: 00d8 gs: 0033 ss: 0068

process test (pid: 17913, ti=f272e000 task=f25ac010 task.ti=f272e000)

stack: f25ac348 00000000 f272ef38 c0429051 00000001 c0879c00 00000001 00000002

f8a41a20 f272ef54 000005dc b7f03000 00000000 eb270540 000005dc f272ef5c

00000040 f272ef74 c049041e 00000001 000005dc eb270540 f8a3f376 f272ef90

call trace:

? finish_task_switch+0x2f/0xb0

? rw_verify_area+0x76/0x97

? scull_write+0x0/0x260 [scull]

? vfs_write+0x84/0xdf

? sys_write+0x3b/0x60

? syscall_call+0x7/0xb

? init_intel_cacheinfo+0x0/0x421

我們希望能夠定於出現bug的地方,在上面的例子中:eip is at scull_write+0x24/0x260 [scull]。表明錯誤的位址在scull的模組中,位於函式scull_write,裡面有兩個數字,可以用來估計在函式中錯誤出現的位置,但這個位置是經過編譯的 位置,函式總長為0x260,錯誤位於0x24,說明在開始部分出現bug。不是所有的bug都能準確定義位置,可以通過call trace來進行估計。stack中列出出問題的部分,這裡可能需要一些經驗,例如如果0xa5a5a5a5a5,可能表示初始分配的空間。在x86中, 預設使用者空間小於0xc0000000,所以上面例子中,猜測f25ac348 為kernel空間。這種看stack的方式我認為比較難,都是估來估去,沒有必要花費力氣在此。

如果整個系統掛起(例如乙個死迴圈引起kernel停止排程,但是在多cpu的系統中,其他的處理器仍可能可以排程,在單cpu系統中,預設 preemption是關閉的,會引起停止排程),就不可能有什麼oops訊息顯示,以前有個專案,開發機在實驗室,我在辦公室遠端呼叫(還不在同一層 樓:(),系統掛機了好幾次,只好不斷地走來走去重啟機器。實驗室的環境過於惡劣,無法忍受。後來想辦法把機器搬上來。但是實際上我們仍有一些方法,要麼 我們需要防止它出現,要麼在之後可以debug。

防止系統整個掛起,可以加入schedule(),例如假設我們能夠在死迴圈中加入schedule()用於觸發排程,允許其他程序從中獲取 cpu時間,這使得我們kill掉程序成為可能。但是如果在正式程式中也使用schedule(),我們需要注意可能由多個程式都會同時使用到 driver,需要加鎖保護,但是不要在乙個持有spinlock的地方呼叫schedule( )。能夠跟蹤debug出現bug的位置,最直接的方式就是在程式中加入printk來進行定位。有時系統只是貌似掛起,實際上仍然可以執行排程,這是可 以使用sysrq鍵(alt-sysrq-x)。具體詳見documentation/sysrq.txt,下面是來自 對這些鍵的介紹:

我們可以通過/proc/sys/kernel/sysrq來設定sysqp鍵是否開啟。另外還有乙個只寫檔案/proc/sysrq- trigger,特別適用於遠端呼叫,例如我們在root下面,echo t > /proc/sysrq-trigger,相當於呼叫了sysrq鍵的x=t的情況,並且不受/proc/sys/kernel/sysrq是否開啟的影 響,我們可以在dmesg或者console中看到相關資訊。而sysrq的p有可能直接指出問題所在。我們還可以使用profiling的功能,但是這 部分ldd3介紹得很簡略,如果需要,詳見:documentation/basic_profiling.txt。ldd3還提了乙個保護我們磁碟的方 式,就是使用唯讀來載入磁碟或者使用nfs的方式,這樣來保障磁碟中的資料不會受到損害。

kernel module程式設計(十) 檢視錯誤

本文也即 linux device drivers ldd3的第四章debuging techniques的讀書筆記之五,但我們不限於此內容。開發中我們不能避免在執行驅動時引起系統fault,但fault並不意味就是panic,linux還是robust的,對於驅動,通常只引 起正在使用該驅動的程序...

我的與kernel module有關的文章

開發篇 核心模組程式設計篇 kernel module程式設計 一 建立乙個小例子 ldd3第二章學習筆記 kernel module程式設計 二 一些古老的記憶 kernel module程式設計 三 獲取 分配或註冊 裝置號 ldd3第三章學習筆記之一 kernel module程式設計 四 裝...

我的與kernel module有關的文章

分享一下我老師大神的人工智慧教程。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智慧的隊伍中來!開發篇 核心模組程式設計篇 kernel module程式設計 一 建立乙個小例子 ldd3第二章學習筆記 kernel module程式設計 二 一些古老的記憶 kernel modul...