Linux核心死機調試方法總結

來源:互聯網
上載者:User

標籤:

使用null 指標和緩衝區溢位是產生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

1. 為了測試GDB操作,故意在kernel/linux/fs/ioctl.c檔案的do_vfs_ioctl方法中加入null 指標作業碼,然後編譯image燒入單板,啟動單板,核心crash,部分log如下: CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 800a73b8, ra == 800a793cOops[#1]:
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開關如下,

Kernel hacking  --->    [*] Kernel debugging    [*] Compile the kernel with debug info編譯核心命令:make kernelbuild,要在project的根目錄下運行該命令進行編譯。啟動GDB命令如下: 3. GDB調試定位Checked call trace log, the most important part in log is “epc” (exception program counter), it is where the crash happened. In this example, the “epc” is 0xc0d1d488. For X1000 and X3500, the address like 0x8XXXXXXXX is in kernel, and the address like 0xcXXXXXXX is in some module.地址0x800a73b8就是對應於地址(do_vfs_ioctl+0x88),後者表示位於函數do_vfs_ioctl的位移地址0x88處。調試過程如下: (gdb) list *(0x800a73b8)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*(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)  可以分析該函數附近代碼發現錯誤位置在line567,test為空白指標(故意在前面賦值NULL)。

 

 

註:如果list*(0x80xxxxxx)命令提示如下資訊:No source file for address 0x80xxxxxx. 原因是沒有在make menuconfig中開啟對應的調試開關進行編譯。

 

 

 

 

 

 

 

 

Linux核心死機調試方法總結

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.