內核oops錯誤調試學習筆記

驅動開發中遇到的 oops 問題,導致內核崩潰,log 一般如下形式

 Unable to handle kernel paging request at virtual address bfb10be0
 pgd = c0003000
 [bfb10be0] *pgd=80000040006003, *pmd=47ab3003, *pte=00000000
 Internal error: Oops: 80000207 [#1] PREEMPT SMP ARM
Modules linked in: wctdm(+) i2s timer pppoe ppp_async brcmfmac pppox ppp_generic nf_conntrack_ipv6 iptable_nat ipt_REJECT ipt_MASQUERADE cfg80211 xt_time xt_tcpudp xt_state xt_nat xt_multiport xt_mark xt_mac xt_limit xt_conntrack xt_comment xt_TCPMSS xt_REDIRECT xt_LOG xt_FLOWOFFLOAD spidev slhc nf_reject_ipv4 nf_nat_redirect nf_nat_masquerade_ipv4 nf_conntrack_ipv4 nf_nat_ipv4 nf_nat nf_log_ipv4 nf_flow_table_hw nf_flow_table nf_defrag_ipv6 nf_defrag_ipv4 nf_conntrack_rtcache nf_conntrack iptable_mangle iptable_filter ip_tables dahdi crc_ccitt compat brcmutil rtc_sunxi ledtrig_heartbeat echo ip6t_REJECT nf_reject_ipv6 nf_log_ipv6 nf_log_common ip6table_mangle ip6table_filter ip6_tables x_tables snd_pcm_oss snd_mixer_oss snd_rawmidi snd_seq_device snd_hwdep [last unloaded: h3i2s]
 CPU: 0 PID: 0 Comm: swapper/0 Tainted: G        W       4.14.63 #0
 Hardware name: Allwinner sun8i Family
task: c0c07080 task.stack: c0c00000
PC is at 0xbfb10be0
 LR is at vchan_complete+0x188/0x1ac

關注點:
PC is at 0xbfb10be0
說明了出錯時的指令位置 0xbfb10be0

1.如何確定 0xbfb10be0 是編進內核裏的函數地址還是insmod 模塊加載的函數地址?
進入內核源碼目錄(編譯過的)
cat System.map

c0008000 T stext
c00080a0 t __create_page_tables
c000817c t __turn_mmu_on_loc
c0008188 t __fixup_smp
c00081f0 t __fixup_smp_on_up
c0008214 t __fixup_pv_table
c0008268 t __vet_atags
c0200000 T __idmap_text_start
c0200000 T __turn_mmu_on
c0200000 T _stext
.....
.....
c0c9d318 b radix_tree_node_cachep
c0c9d31c B __bss_stop
c0c9d31c B _end

看在不在其中,不在則說明是在 insmod 加載的模塊裏。

2.如果在 insmod 加載的模塊裏 ,如何確定是在哪一個ko 裏?
答:通過查看/proc/kallsyms 來確定。
cat /proc/kallsyms | grep 0xbfb10b

/proc/kallsyms 的內容節選如下,其中右邊 [ ] 裏的就是所在驅動名

bf000084 t snd_hwdep_poll       [snd_hwdep]
bf000a04 t snd_hwdep_ioctl      [snd_hwdep]
bf0000ac t snd_hwdep_mmap       [snd_hwdep]
bf000544 t snd_hwdep_open       [snd_hwdep]
bf0004b8 t snd_hwdep_release    [snd_hwdep]
bf0000d4 t snd_hwdep_dev_free   [snd_hwdep]
bf000334 t snd_hwdep_dev_register       [snd_hwdep]
bf000238 t snd_hwdep_dev_disconnect     [snd_hwdep]
bf000cdc t cleanup_module       [snd_hwdep]
bf000110 T snd_hwdep_new        [snd_hwdep]

由此可以根據 PC is at 0xbfb10be0 確定是哪個模塊的,同時還可以確定是哪個函數裏。

3.反彙編 找到指令位置
如果是確定是在.ko 裏,直接反彙編 .ko ,.ko反匯編出來的地址是從0開始。
xxx-objdump -D xxx.ko > xxx.dis

如果是編譯進內核裏,要反彙編整個內核的話,時間要很久!
這裏從網上找到一個快速高效的腳本 objdump_func.sh :

#!/bin/bash

vmlinux=$1 
symbol=$2 
 
if [ -z "$vmlinux" ]; then 
    echo "usage : $0 vmlinux symbol"
    exit 
fi 
#這裏指定你 objdump 的路徑
objdump=~/work/openwrt/arm-openwrt-linux-objdump
 
startaddress=$(nm -n $vmlinux | grep "\w\s$symbol" | awk '{print "0x"$1;exit}') 
endaddress=$(nm -n $vmlinux | grep -A1 "\w\s$symbol" | awk '{getline; print "0x"$1;exit}') 
  
if [ -z "$symbol" ]; then 
    echo "dump all symbol"
    $objdump -d $vmlinux 
else 
    echo "start-address: $startaddress, end-address: $endaddress" 
    $objdump -d $vmlinux --start-address=$startaddress --stop-address=$endaddress
fi

使用方法 ./objdump_func.sh vmlinux xx_func > xxx.dis

cat xxx.dis 找到指令位置,分析彙編代碼,找到出錯原因。這十分考驗讀彙編能力。

鳴謝:要感謝韋東山老師,以上知識學習自韋老師的二期視頻。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章