1.首先在編譯生成內核的時候同時生成了一個vmlinux,使用gdb。
在內核配置時,make menuconfig 要打開complie with debug info選項。
注意這行: PC is at skb_release_data+0x74/0xc4
這告訴我們,skb_release_data函數有0xc4這麼大,而Oops發生在0x74處。 那麼我們先看一下skb_release_data從哪裏開始:
# grep skb_release_data ./System.map
c0282af4 t skb_release_data
於是我們知道在系統出現錯誤時程序指針在 c0282af4+0x74=c0282b68
2.然後用gdb查看,gdb ./vmlinux (在linux目錄下執行),進入調試模式。
(gdb) b *0xc0282b68
Breakpoint 1 at 0xc0282b68: file net/core/skbuff.c ,line312
這就是告訴我們在哪個文件,在哪一行。如此知道了錯誤的位置,具體的原因帶解決。
3,反彙編
(gdb) disassemble 0xc0282b68
內核開發時有時候出現Oops,例如一個野指針會導致內核崩潰,如運行時出現以下log:現在有三種方法可以找出具體出現野指針的地方
- 5.438972] bells bells: wm5102-aif1 <-> samsung-i2s.0 mapping ok
- [ 5.443812] bells bells: Failed to add route OPCLK->Sub CLK_SYS
- [ 5.450499] Unable to handle kernel NULL pointer dereference at virtual address 00000010
- [ 5.457770] pgd = c0004000
- [ 5.460504] [00000010] *pgd=00000000
- [ 5.463959] Internal error: Oops: 5 [#1] PREEMPT SMP ARM
- [ 5.469249] CPU: 3 Not tainted (3.4.5-g092c4c5 #75)
- [ 5.474457] <span style="color:#990000;">PC is at snd_soc_dai_set_sysclk+0x10/0x84</span>
- [ 5.479481] LR is at bells_late_probe+0x60/0x198
- [ 5.484133]<span style="color:#FFCC33;"> pc : [<c040faa0>]</span> lr : [<c0424030>] psr: 60000013
- [ 5.484139] sp : d683bd58 ip : d683bd80 fp : d683bd7c
- [ 5.495579] r10: 00000000 r9 : c08a41f8 r8 : 00000000
- [ 5.500723] r7 : d62bf400 r6 : 00000000 r5 : d69ab800 r4 : 00000000
- [ 5.507284] r3 : 00000000 r2 : 00000000 r1 : 00000002 r0 : 00000000
- [ 5.513731] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
- [ 5.521074] Control: 10c5387d Table: 4000406a DAC: 00000015
- [ 5.526799]
- [ 5.526802] PC: 0xc040fa20:
0 直接通過addr2line命令獲取,例如:
$ arm-none-linux-gnueabi-addr2line -e vmlinux c040faa0
注:請確保CROSS_COMPILE跟你編譯用的是一樣的前綴,例如上面的arm-none-Linux-gnueabi-,你編譯時也必須是這個,不然算出來的行號可能會偏差比較大。
addr2line 代碼如下
- #!/bin/bash
- #
- # addr2line.sh -- Convert PC address to source code line, open the file and point to the line
- #
- ADDR=$1
- [ -z "$ADDR" ] && echo -e "Usage: Please specify the PC address\n $0 PC_ADDR" && exit 1
- [ -z "$CROSS_COMPILE" ] && CROSS_COMPILE=arm-none-linux-gnueabi-
- ADDR2LINE=${CROSS_COMPILE}addr2line
- file_line=`$ADDR2LINE -e vmlinux $ADDR`
- if [ "$file_line" == "??:0" ]; then
- echo "ERROR: Can not find the line for $ADDR"
- exit 2
- else
- vim -c "set number" -c "set fdm=manual" $(echo $file_line | sed -e "s/:/ +/g")
- fi
1 通過gdb定位
1.2 設置斷點,即上面log信息中的用黃色重點標記的pc地址
2 根據查詢內核符號表和反彙編信息定位,它可以不依賴出錯內核的vmlinux