使用空指針和緩沖區溢出是產生oops的兩個最常見原因。
1、直接查看oops信息,首先查找源代碼發生oops的位置,通過查看指令寄存器EIP的值,可以找到位置。再查找函數調用棧可以得到更多的信息。從函數調用棧可辨別出局部變量,全局變量和函數參數。較為重要的信息就是指令指針(EIP),即出錯指令的地址。
例如:在函數faulty_read的oops信息的函數調用棧中,棧頂為ffffffff,棧頂值應為一個小於ffffffff的值,為此值,說明再找不回調用函數地址,說明有可能因緩沖區溢出等原因造成指針錯誤。
如果oops信息顯示觸發oops的地址為0xa5a5a5a5,則說明很可能是因為沒有初始化動態內存引起的。
2、使用\prebuilts\gcc\linux-x86\arm\arm-eabi-4.7\bin\arm-eabi-addr2line命令找到地址對應的程序位置,顯示對應的程序文件名和行號。
1.arm-eabi-addr2line 將類似libxxx.so 0x00012345的調用棧16進制值翻譯成文件名和函數名
arm-eabi-addr2line -e libxxx.so 0x00012345
2.arm-eabi-nm 列出文件的符號信息
arm-eabi-nm -l -C -n -S libdvm.so > dvm.data
3.arm-eabi-objdump 列出文件的詳細信息
arm-eabi-objdump -C -d libc.so > libc.s
通過以上工具的分析 ,我們可以得到較完整的調用棧以及調用邏輯的匯編碼。
addr2line -e -f libc.so 0001173c
objdump -S -D libc.so > deassmble_libc.txt
打開這個反匯編過后的重定向文件,在查詢的時候輸入1173c這個偏移地址,你會看到在茫茫人海中
00011684 <pthread_create>:
11684: e92d4ff0 push {r4, r5, r6, r7, r8, r9, sl, fp, lr}
11688: e24dd01c sub sp, sp, #28 ; 0x1c
1168c: e1a06001 mov r6, r1
11690: e1a08002 mov r8, r2
11694: e1a09003 mov r9, r3
11698: e3a04001 mov r4, #1 ; 0x1
1169c: e59f521c ldr r5, [pc, #540] ; 118c0 <pthread_create+0x23c>
116a0: e58d000c str r0, [sp, #12]
116a4: eb009a35 bl 37f80 <strncmp+0x20>
116a8: e59f2214 ldr r2, [pc, #532] ; 118c4 <pthread_create+0x240>
116ac: e1a03000 mov r3, r0
116b0: e1a01004 mov r1, r4
116b4: e593c000 ldr ip, [r3]
116b8: e3a0003c mov r0, #60 ; 0x3c
116bc: e08f3005 add r3, pc, r5
116c0: e7933002 ldr r3, [r3, r2]
116c4: e5834000 str r4, [r3]
116c8: e58dc010 str ip, [sp, #16]
116cc: eb009a3b bl 37fc0 <strncmp+0x60>
...
1173c: ebffec2b bl c7f0 <__pthread_clone>-->就是他了,對你成功了。
...
3、在分析轉儲映像之前,用戶應重啟動進入一個穩定的內核。用戶可以用GDB對拷貝出的轉儲進行有限分析。編譯vmlinux時應加上-g選項,才能生成調試用的符號,然后,用下面的命令調試vmlinux:
gdb vmlinux <dump-file>
首先 objdump -D vmlinx 反匯編你的內核
然后 你可以通過以下幾個寄存器來判斷:
1. epc 掛在哪個函數里
2. ra 函數的返回地址,
3. Cause 通過這個寄存器可以分析是什么類型的異常.
4、通過cat /proc/modules獲得模塊內核鏈接基地址,用死機地址減去鏈接基地址得到模塊內偏移,再反匯編,找該偏移對應的函數就找到了死機函數。
用objdump -d test.ko > test.asm的話。可以將模塊文件反匯編。但是因為模塊是目標文件,所以會看到,text段的地址是從0開始的。而該模塊在內核在運行的時候,該模塊的代碼段顯然不是在0地址。另外,該代碼段中你會看到函數間調用,以及函數內部跳轉都是用的b開頭的分支指令(僅限於mips和arm的體系結構的討論),分支指令跳轉是以pc為基准值前后跳轉的。除非,跳轉符號不屬於這個模塊,則需要32位的跳轉。實際上,模塊鏈接到內核的時候,模塊的代碼段是作為一個整體鏈接到內核,所以我們只需要知道模塊鏈接到的基地址,再用死機的地址減去這個基地址這就得到了,該地址在模塊中代碼段的偏移,再通過剛才的反匯編文件就找到了是死在那個函數中。而要得到各個模塊的鏈接地址就很簡單了,直接cat /proc/modules就得到了。需要注意的是用__init修飾了的模塊初始化函數,是放在單獨的段的,通常叫.init.text 。該段會在模塊初始化完成后內存就釋放掉了
5、google提供了一個python腳本,可以從 http://code.google.com/p/android-ndk-stacktrace-analyzer/ 下載這個python腳本,然后使用
adb logcat -d > logfile 導出 crash 的log,
使用 arm-eabi-objdump (位於build/prebuilt/linux-x86/arm-eabi-4.2.1/bin下面)把so或exe轉換成匯編代碼,如:
arm-eabi-objdump -S mylib.so > mylib.asm,
然后使用腳本
python parse_stack.py <asm-file> <logcat-file>
http://blog.csdn.net/lickylin/article/details/19172725
如上崩潰信息,可知發生崩潰的函數為rb_init_debugfs,崩潰的地址為0x804386f8
1>在linux下,到工程的如下目錄下:kernel/linux,找到文件vmlinux,執行命令gdb vmlinux:
在gdb命令下執行如下命令即可查找到出錯函數所在的文件與行數
(gdb) b *0x804386f8
2>如果不確定崩潰的地址是否是0x804386f8,可以在文件System.map中
查找函數rb_init_debugfs獲取該函數的地址,然后加上偏移地址(本例中偏移地址為0x14 rb_init_debugfs+0x14/0x70)即可。
3>直接函數名加偏移量也可以
(gdb) b *rb_init_debugfs+0x14
上面是出錯模塊是編譯進內核的,對於編譯進內核的模塊可以通過gdb vmlinux來確定出錯函數所在的文件與行數。
那如果出錯模塊是動態加載進內核的該怎么辦呢?
這就需要使用objdump進行反匯編操作了,使用如下命令,就會將C語言與匯編語言同時顯示(需要加-g命令)
#objdump -S **.o -g
如果使用上面命令,還是只顯示匯編,而沒有c語言的話,不用擔心,在你編譯驅動模塊的Makefile中,編譯成.o文件時,增加-g選項,
對於新生成的.o文件再使用上面的命令就 可以看到匯編與c語言共存了。然后根據kernel panic提示中顯示的函數名加上偏移量就能找到出錯行了。
http://blog.csdn.net/wuruixn/article/details/38320643
Cpu 0
$ 0 : 00000000 10008d00 00000000 ffffffea
$ 4 : fffffdfd 10008d01 00000001 00000000
$ 8 : 00000000 7fed2e40 00001cb2 00000b3b
$12 : 00031c7f 2ab5ead7 2aaac7c9 15010000
$16 : 7fed2e18 878ca5a0 00000000 00000001
$20 : 2ab84980 00000000 00000007 00000000
$24 : 00000000 2ab62090
$28 : 8782c000 8782fe98 7fed2fc8 800a793c
Hi : 0000002a
Lo : 000311fc
epc : 800a73b8 do_vfs_ioctl+0x88/0x5c8
Not tainted
ra : 800a793c sys_ioctl+0x44/0x98
Status: 10008d03 KERNEL EXL IE
Cause : 00000008
BadVA : 00000000
PrId : 0002a080 (Broadcom4350)
Modules linked in:
Process init (pid: 1, threadinfo=8782c000, task=8782bb68, tls=00000000)
Stack : 878ca1a0 00000004 00000000 10008d00 00000603 2aabcfff 87b0bea8 00000001
87beeaf0 2aabc000 2aabd000 87aa9cb0 2aabd000 2aabd000 8782ff08 fffffff8
00000001 7fed3258 00000007 00000000 878ca5a0 0000540d 00000000 00000001
2ab84980 800a793c 08100871 00000001 87bea41c 0000fff2 00000000 2abbdff0
7fed2e18 00000001 7fed2e60 2abbdff0 00000120 8001ba7c 00000000 00000000
...
Call Trace:(--Raw--
[<800a793c>] sys_ioctl+0x44/0x98
[<8001ba7c>] stack_done+0x20/0x3c
Call Trace:
[<800a73b8>] do_vfs_ioctl+0x88/0x5c8
[<800a793c>] sys_ioctl+0x44/0x98
[<8001ba7c>] stack_done+0x20/0x3c
Code: 0c029c9f 02003021 8fbf0064 <8c020000> 8fb40060 8fb3005c 8fb20058 8fb10054 8fb00050
Disabling lock debugging due to kernel taint
Kernel panic - not syncing: Attempted to kill init!
Rebooting in 1 seconds..<6>
stopping CPU 1
kerSysMipsSoftReset: called on cpu 0
2. 啟動GDB, 直接在主機(開發機)控制台運行gdb工具(或./mips-linux-uclibc-gdb),然后敲入 file ...../vmlinux啟動帶調試信息的內核,注意此時要配置內核debug開關重新編譯內核生成文件vmlinux(比之前的文件大10倍左右,50M以上),配置內核debug開關如下,
564 error = vfs_ioctl(filp, cmd, arg);
565 break;
566 }
567 error = *test;
568 return error;
569 }
570
571 SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
572 {
573 struct file *filp;
(gdb) list*(do_vfs_ioctl+0x88)
0x800a73b8 is in do_vfs_ioctl (fs/ioctl.c:569).
564 error = vfs_ioctl(filp, cmd, arg);
565 break;
566 }
567 error = *test;
568 return error;
569 }
570
571 SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
572 {
573 struct file *filp;
(gdb) list*(sys_ioctl+0x44)
注:如果list*(0x80xxxxxx)命令提示如下信息:No source file for address 0x80xxxxxx. 原因是沒有在make menuconfig中打開對應的調試開關進行編譯。