新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM Linux內核驅動異常定位方法分析反匯編方式

        ARM Linux內核驅動異常定位方法分析反匯編方式

        作者: 時間:2016-11-09 來源:網絡 收藏
        最近在搞Atmel 的SAM9x25平臺,Linux系統,用于工業設備。這也是我首次參與工業設備的研發。在調試Atmel SAM9x25的Linux串口設備的時候,發現無論是讀還是寫,都會產生異常。相關的異常信息如下:

        ==================================================================================================================

        本文引用地址:http://www.104case.com/article/201611/317993.htm

        Unable to handle kernel NULL pointer dereference at virtual address 00000000
        pgd = c0004000
        [00000000] *pgd=00000000
        Internal error: Oops: 17 [#1]
        last sysfs file: /sys/devices/virtual/vc/vcsa1/dev
        Modules linked in:
        CPU: 0 Not tainted (2.6.39 #1)
        PC is at atmel_tasklet_func+0x110/0x69c
        LR is at atmel_tasklet_func+0x10/0x69c
        pc : [] lr : [] psr: 20000013
        sp : c7825f50 ip : c045e0bc fp : 00000000
        r10: c0456a80 r9 : 0000000a r8 : 00000000
        r7 : c7874568 r6 : c045e0a8 r5 : 00000100 r4 : c045dfb4
        r3 : 00000002 r2 : 00000ffc r1 : 00000001 r0 : 00000001
        Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
        Control: 0005317f Table: 27aec000 DAC: 00000017
        Process ksoftirqd/0 (pid: 3, stack limit = 0xc7824270)
        Stack: (0xc7825f50 to 0xc7826000)
        5f40: 00000100 c7824000 00000001 00000018
        5f60: 0000000a c0456a80 c7825f84 00000000 00000100 c7824000 00000001 00000018
        5f80: c0456a80 c0047b70 00000006 c0047650 c0432e50 00000000 c7824000 00000000
        5fa0: 00000000 c0047938 00000000 00000000 00000000 c00479a0 c7825fd4 c7819f60
        5fc0: 00000000 c0058c64 c00335f4 00000000 00000000 00000000 c7825fd8 c7825fd8
        5fe0: 00000000 c7819f60 c0058be0 c00335f4 00000013 c00335f4 0c200050 fc3b9beb
        [] (atmel_tasklet_func+0x110/0x69c) from [] (tasklet_action+0x80/0xe4)
        [] (tasklet_action+0x80/0xe4) from [] (__do_softirq+0x74/0x104)
        [] (__do_softirq+0x74/0x104) from [] (run_ksoftirqd+0x68/0x108)
        [] (run_ksoftirqd+0x68/0x108) from [] (kthread+0x84/0x8c)
        [] (kthread+0x84/0x8c) from [] (kernel_thread_exit+0x0/0x8)
        Code: 1a000002 e59f057c e59f157c ebfa416c (e5983000)
        ---[ end trace 6b8e1841ba3a56c9 ]---
        Kernel panic - not syncing: Fatal exception in interrupt
        [] (unwind_backtrace+0x0/0xf0) from [] (panic+0x54/0x178)
        [] (panic+0x54/0x178) from [] (die+0x17c/0x1bc)
        [] (die+0x17c/0x1bc) from [] (__do_kernel_fault+0x64/0x84)
        [] (__do_kernel_fault+0x64/0x84) from [] (do_page_fault+0x1b8/0x1cc)
        [] (do_page_fault+0x1b8/0x1cc) from [] (do_DataAbort+0x38/0x9c)
        [] (do_DataAbort+0x38/0x9c) from [] (__dabt_svc+0x4c/0x60)
        Exception stack(0xc7825f08 to 0xc7825f50)
        5f00: 00000001 00000001 00000ffc 00000002 c045dfb4 00000100
        5f20: c045e0a8 c7874568 00000000 0000000a c0456a80 00000000 c045e0bc c7825f50
        5f40:c01a4e30 c01a4f3020000013 ffffffff
        [] (__dabt_svc+0x4c/0x60) from [] (atmel_tasklet_func+0x110/0x69c)
        [] (atmel_tasklet_func+0x110/0x69c) from [] (tasklet_action+0x80/0xe4)
        [] (tasklet_action+0x80/0xe4) from [] (__do_softirq+0x74/0x104)
        [] (__do_softirq+0x74/0x104) from [] (run_ksoftirqd+0x68/0x108)
        [] (run_ksoftirqd+0x68/0x108) from [] (kthread+0x84/0x8c)
        [] (kthread+0x84/0x8c) from [] (kernel_thread_exit+0x0/0x8)

        ==================================================================================================================

        通常認為,產生異常的地址是lr寄存器的值,從上面的異常信息可以看到[lr]的值是c01a4e30。

        接下來,我們可以通過內核鏡像文件反匯編來找到這個地址。內核編譯完成后,會在內核代碼根目錄下生成vmlinux文件,我們可以通過以下命令來反匯編:

        arm-none-eabi-objdump -Dz-Svmlinux >linux.dump

        值得注意的是,arm-none-eabi-objdump的參數-S表示盡可能的把原來的代碼和反匯編出來的代碼一起呈現出來,-S參數需要結合arm-linux-gcc編譯參數-g,才能達到反匯編時同時輸出原來的代碼。所以,我在linux內核代碼根目錄的Makefile中增加-g編譯參數:

        KBUILD_CFLAGS :=-g-Wall -Wundef -Wstrict-prototypes -Wno-trigraphs
        -fno-strict-aliasing -fno-common
        -Werror-implicit-function-declaration
        -Wno-format-security
        -fno-delete-null-pointer-checks

        修改Makefile后,重新編譯內核,在根目錄中生成的vmlinux文件就會包含了原來的代碼信息,因此,該文件的大小也比原來大一倍!

        最后執行“arm-none-eabi-objdump -Dz-Svmlinux >linux.dump”,由于加入了-g編譯參數,執行這個反匯編命令需要很長時間(本人在虛擬機上執行,花了近6個小時!),反匯編出來的linux.dump文件也比原來的44MB增大到驚人的503MB。

        接下來可以用UltraEdit打開linux.dump文件,查找“c01a4e30”字符串。

        最后定位到的信息是:

        ==================================================================================================================

        /*
        * tasklet handling tty stuff outside the interrupt handler.
        */
        static void atmel_tasklet_func(unsigned long data)
        {
        c01a4e20:e92d45f0 push{r4, r5, r6, r7, r8, sl, lr}
        c01a4e24:e24dd01c subsp, sp, #28; 0x1c
        c01a4e28:e1a04000 movr4, r0
        /* The interrupt handler does not take the lock */
        spin_lock(&port->lock);

        if (atmel_use_pdc_tx(port))
        atmel_tx_pdc(port);
        else if (atmel_use_dma_tx(port))
        c01a4e2c:ebfffda1 blc01a44b8
        c01a4e30:e3500000 cmpr0, #0; 0x0
        c01a4e34:e5943034 ldrr3, [r4, #52]
        c01a4e38:0a00007b beqc01a502c

        ==================================================================================================================

        可以看出來,異常的產生位于atmel_tasklet_func函數的else if (atmel_use_dma_tx(port))一行。

        估計atmel_use_dma_tx(port)的“port”參數為空指針所致!

        最后,我把串口的DMA功能去掉,改為直接傳送,這樣做雖然效率低了點,但產生異常的現象消失了。

        到后面再仔細分析為什么會產生這個異常,徹底解決這個問題。



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 黄梅县| 巩留县| 三明市| 中卫市| 通榆县| 米泉市| 成都市| 大港区| 内乡县| 蒲城县| 台江县| 江孜县| 溧水县| 南昌县| 封丘县| 重庆市| 大连市| 板桥市| 耿马| 石渠县| 旺苍县| 冷水江市| 万山特区| 盐亭县| 奉新县| 沛县| 乐亭县| 双流县| 集贤县| 望谟县| 克什克腾旗| 集安市| 壤塘县| 舟曲县| 张家港市| 兰考县| 锦屏县| 玉溪市| 西乡县| 剑河县| 盐源县|