ARM Linux核心驅動異常定位方法分析–反組譯碼方式

來源:互聯網
上載者:User

原創作品,轉載請以超連結形式說明出處!

 

原文連結:http://blog.csdn.net/hunhunzi/article/details/7052032

最近在搞Atmel 的SAM9x25平台,Linux系統,用於工業裝置。這也是我首次參與工業裝置的研發。在調試Atmel SAM9x25的Linux串口裝置的時候,發現無論是讀還是寫,都會產生異常。相關的異常資訊如下:

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

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 : [<c01a4f30>]    lr : [<c01a4e30>]    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
[<c01a4f30>] (atmel_tasklet_func+0x110/0x69c) from [<c0047b70>] (tasklet_action+0x80/0xe4)
[<c0047b70>] (tasklet_action+0x80/0xe4) from [<c0047650>] (__do_softirq+0x74/0x104)
[<c0047650>] (__do_softirq+0x74/0x104) from [<c00479a0>] (run_ksoftirqd+0x68/0x108)
[<c00479a0>] (run_ksoftirqd+0x68/0x108) from [<c0058c64>] (kthread+0x84/0x8c)
[<c0058c64>] (kthread+0x84/0x8c) from [<c00335f4>] (kernel_thread_exit+0x0/0x8)
Code: 1a000002 e59f057c e59f157c ebfa416c (e5983000) 
---[ end trace 6b8e1841ba3a56c9 ]---
Kernel panic - not syncing: Fatal exception in interrupt
[<c0037784>] (unwind_backtrace+0x0/0xf0) from [<c00429f4>] (panic+0x54/0x178)
[<c00429f4>] (panic+0x54/0x178) from [<c0035a18>] (die+0x17c/0x1bc)
[<c0035a18>] (die+0x17c/0x1bc) from [<c00386c4>] (__do_kernel_fault+0x64/0x84)
[<c00386c4>] (__do_kernel_fault+0x64/0x84) from [<c003889c>] (do_page_fault+0x1b8/0x1cc)
[<c003889c>] (do_page_fault+0x1b8/0x1cc) from [<c002c2f0>] (do_DataAbort+0x38/0x9c)
[<c002c2f0>] (do_DataAbort+0x38/0x9c) from [<c003234c>] (__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 c01a4f30 20000013 ffffffff
[<c003234c>] (__dabt_svc+0x4c/0x60) from [<c01a4f30>] (atmel_tasklet_func+0x110/0x69c)
[<c01a4f30>] (atmel_tasklet_func+0x110/0x69c) from [<c0047b70>] (tasklet_action+0x80/0xe4)
[<c0047b70>] (tasklet_action+0x80/0xe4) from [<c0047650>] (__do_softirq+0x74/0x104)
[<c0047650>] (__do_softirq+0x74/0x104) from [<c00479a0>] (run_ksoftirqd+0x68/0x108)
[<c00479a0>] (run_ksoftirqd+0x68/0x108) from [<c0058c64>] (kthread+0x84/0x8c)
[<c0058c64>] (kthread+0x84/0x8c) from [<c00335f4>] (kernel_thread_exit+0x0/0x8)

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

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

接下來,我們可以通過核心鏡像檔案反組譯碼來找到這個地址。核心編譯完成後,會在核心代碼根目錄下產生vmlinux檔案,我們可以通過以下命令來反組譯碼:

arm-none-eabi-objdump -Dz
-S vmlinux >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-S
vmlinux >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  sub sp, sp, #28 ; 0x1c
c01a4e28: e1a04000  mov r4, 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  bl c01a44b8 <atmel_use_dma_tx>
c01a4e30: e3500000  cmp r0, #0 ; 0x0
c01a4e34: e5943034  ldr r3, [r4, #52]
c01a4e38: 0a00007b  beq c01a502c <atmel_tasklet_func+0x20c>

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

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

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

 

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

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

 

關鍵字:ARM atmel  SAM9x25 Linux核心驅動異常 調試 反組譯碼 objdump

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.