1. 程式人生 > >根據核心Oops 定位程式碼

根據核心Oops 定位程式碼

核心開發時有時候出現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] PC is at snd_soc_dai_set_sysclk+0x10/0x84
[ 5.479481] LR is at bells_late_probe+0x60/0x198 [ 5.484133] pc : [<c040faa0>] 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.1 首先執行gdb,不過需要使用出錯核心的vmlinux
執行 $ arm-linux-gnueabi-gdb vmlinux
1.2 設定斷點,即上面log資訊中的用黃色重點標記的pc地址
執行 (gdb) b*0xc040faa0 Breakpoint 1 at 0xc040faa0: file sound/soc/soc-core.c, line 1070.
此時,我們知道了在 sound/soc/soc-core.c檔案的1070行出錯,這下我們就鎖定了範圍,具體解決了;
1.3 如果你不想再另開啟一個視窗去看該函式,也可以直接在當前視窗檢視該函式
(gdb) set listsize 50(設定顯示50行的內容) (gdb) list *0xc040faa0(檢視顯示的內容)

2 根據查詢核心符號表和反彙編資訊定位,它可以不依賴出錯核心的vmlinux

2.1 根據上面紅色標記的log資訊,PC is at snd_soc_dai_set_sysclk+0x10/0x84 0x10:表示出錯的偏移位置,0x84表示snd_soc_dai_set_sysclk函式的大小
2.2 現在就是找到snd_soc_dai_set_sysclk函式的位置, $ arm-linux-gnueabi-nm vmlinux | grep snd_soc_dai_set_sysclk c04116bc T snd_soc_dai_set_sysclk
$ arm-linux-gnueabi-objdump -S vmlinux –start-address=0xc04116bc –stop-address=0xc04116bc > ~/temp/soc  2.3 接下來就去檢視vim ~/temp/soc檔案, 找到0xc04116bc+0x10的位置即可