PowerPC構架系統的linux內核和內核模塊調試

說明:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

   此文檔的目標系統爲freescale MPC8349E-mITX,調試工具爲BDI2000, 目標系統採用2.6內核,對其他採用POWERPC,MIPSARM的芯片的系統亦具有參考意義。 此文檔中內核調試爲了簡化,採用目標系統中的UBOOT初始化目標板,並通過UBOOT或者BDI2000加載內核到目標板的RAM中。

 

1. BDI2000配置:

 

下面是MPC8349E-mITXBDI2000配置文件,

  1. ; BDI-2000 Configuration file for the MPC8349E-mITX
  2. ; Tip: If after a reset, the BDI-2000 fails to halt at 0x100,
  3. ; you may need to power-down the board for a few seconds.
  4. [INIT]
  5. ; we use UBOOT to initialize the board
  6. [TARGET]
  7. CPUTYPE     8349
  8. JTAGCLOCK   1
  9. ;STARTUP     RESET
  10. STARTUP     RUN
  11. BREAKMODE   HARD
  12. STEPMODE    HWBP
  13. BOOTADDR    0x00000100
  14. ;If you're getting "Writing to workspace failed" errors during flash operations,
  15. ;then try uncommenting this line instead.  This moves the flash window to
  16. ;high memory, leaving low memory available for DDR.
  17. RCW         0xb060a000 0x04040000 ;Set the HRCW to boot the image at 0xFE000000
  18. MMU         XLAT ;0xc0000000
  19. PTBASE      0xf0 ;
  20. [HOST]
  21. IP          192.168.7.90
  22. FILE        $u-boot.bin
  23. LOAD        MANUAL
  24. PROMPT      8349E-mITX-GP>
  25. DUMP        itx-dump.bin
  26. [FLASH]
  27. CHIPTYPE    AM29BX16
  28. CHIPSIZE    0x800000
  29. BUSWIDTH    16
  30. ;WORKSPACE   0x1000
  31. FORMAT      BIN 0xfe000000
  32. ;flash_image.bin is an image file of an entire 8MB flash region.
  33. ;Flash this file at 0xfe0000000 to restore all of flash.
  34. ;ERASE 0xFE000000 0x10000 127 ; 127 sectors @ 64KB each
  35. ;ERASE 0xFE7F0000 0x2000 8 ; 8 sectors @ 8KB each
  36. ;FILE $flash_image.bin
  37. ;Use these lines if you just want to flash U-Boot
  38. ERASE       0xfe000000 0x10000  4; Erase 384KB, each sector is 64KB
  39. FILE        mpc8349e/u-boot131-mitx-gp.bin
  40.  [REGS]
  41. FILE        $reg8349e.def

以上配置文件的【HOST】段的IP要改爲主機IP,關鍵的字段MMU         XLAT PTBASE POWERPCMIPS經常需要設置的,關於PTBASE的具體設置,超出本文範圍,詳細情況請參考BDI2000的手冊

 

 

2.內核修改和配置

 爲了能夠調試內核,需要在內核中的Makefile中增加如下調試選項:

    CFLAGS 增加C代碼調試選項-g –ggdb

    AFLAGS 增加彙編代碼調試選項:-Wa,-L -gdwarf-2

   去掉CFLAGS編譯選項中-fomit-frame-pointer

GCC-fomit-frame-pointer選項是優化函數棧回溯(stack backtrace)的,我們調試的時候需要提供函數回溯能力,所以我們要去掉這個選項,當然,有的系統系統不受它的影響,或者說它不起作用,爲了統一,我們統一去掉它。

 

相對個案來說,我是做如下改動的:

  1. -- Makefile      2008-07-08 03:07:38.000000000 +0800
  2. +++ Makefile.debug       2008-07-08 03:06:04.000000000 +0800
  3. -CPPFLAGS        := -D__KERNEL__ $(LINUXINCLUDE)
  4. +ifdef CONFIG_DEBUG_INFO
  5. +
  6. +        CPPFLAGS        := -D__KERNEL__ $(LINUXINCLUDE) -g -ggdb
  7. -CFLAGS          := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs /
  8. +        CFLAGS         := $(CPPFLAGS) -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs /
  9.                     -fno-strict-aliasing -fno-common
  10. -AFLAGS          := -D__ASSEMBLY__
  11. +        AFLAGS          := -D__ASSEMBLY__ -Wa,-L -gdwarf-2
  12. +else
  13. +        CPPFLAGS        := -D__KERNEL__ $(LINUXINCLUDE)
  14. +        CFLAGS          := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs /
  15. +                   -fno-strict-aliasing -fno-common
  16. +        AFLAGS          := -D__ASSEMBLY__
  17. +
  18. +endif
  19. @@ -491,27 +500,33 @@ 
  20.  # Defaults vmlinux but it is usually overridden in the arch makefile 
  21.  all: vmlinux
  22. -ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
  23. -CFLAGS                          += -Os
  24. -else
  25. -CFLAGS                          += -O2
  26. -endif
  27.  include $(srctree)/arch/$(ARCH)/Makefile
  28. -ifdef CONFIG_FRAME_POINTER
  29. -CFLAGS                          += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
  30. -else
  31. -CFLAGS                          += -fomit-frame-pointer
  32. -endif
  33.  ifdef CONFIG_UNWIND_INFO
  34.  CFLAGS                          += -fasynchronous-unwind-tables
  35.  endif
  36. -ifdef CONFIG_DEBUG_INFO
  37. -CFLAGS                          += -g
  38. -endif
  39. +#ifdef CONFIG_DEBUG_INFO
  40. +CFLAGS          += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
  41. +CFLAGS                         += -g -ggdb
  42. +CFLAGS                         += -O
  43. +#else
  44. +
  45. +#      ifdef CONFIG_FRAME_POINTER
  46. +                        CFLAGS          += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
  47. +#      else
  48. +                        CFLAGS          += -fomit-frame-pointer
  49. +#      endif
  50. +        
  51. +#      ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
  52. +                        CFLAGS          += -Os
  53. +#      else
  54. +        CFLAGS          += -O2
  55. +#      endif
  56. +
  57. +#endif

通過以上修改後,系統的的調試信息簡單的通過CONFIG_DEBUG_INFO宏來控制了,那麼CONFIG_DEBUG_INFO宏又是從哪裏來的呢?它其實是從內核的配置文件.config裏面來的。

 

一般內核通過make menuconfig做配置的時候,都有

Kernel hacking  --->

[*] Kernel debugging

[*] Compile the kernel with debug info

[*] Force gcc to inline functions marked 'inline'  2.6比較新的內核有這一項)

[*] Include BDI-2000 user context switcher    (有的系統直接提供了這個選項,它和BDI2000PTBASE設置配合

 

通過保存後,以上選項會生成如下配置選項:

CONFIG_DEBUG_KERNEL=y

CONFIG_DEBUG_INFO=y

CONFIG_FORCED_INLINING=y

CONFIG_BDI_SWITCH=y

 

值得關注的是PowerPC內核中CONFIG_BDI_SWITCH,它到底在內核中怎樣起作用的?

我們看arch/powerpc/kernel/head_32.S的關鍵代碼:

/* Load up the kernel context */

2:      bl          load_up_mmu

 

#ifdef CONFIG_BDI_SWITCH

        /* Add helper information for the Abatron bdiGDB debugger.

         * We do this here because we know the mmu is disabled, and

         * will be enabled for real in just a few instructions.

         */

        lis         r5, abatron_pteptrs@h

        ori        r5, r5, abatron_pteptrs@l

        stw       r5, 0xf0(r0)       /* This much match your Abatron config */

        lis         r6, swapper_pg_dir@h

        ori        r6, r6, swapper_pg_dir@l

        tophys(r5, r5)

        stw       r6, 0(r5)

#endif /* CONFIG_BDI_SWITCH */

 

/* Now turn on the MMU for real! */

 

它在MMU真正時能之前先增加了BDI2000幫助信息。在arch/powerpc/kernel/head_32.S的最後通過abatron_pteptrs保留了8個自己的空間給BDI2000用於保存2個頁表指針,如下:

/* Room for two PTE pointers, usually the kernel and current user pointers

 * to their respective root page table.

 */

abatron_pteptrs:

        .space   8

 

3. 內核調試

通過以上的準備工作,就可以進行內核和模塊的調試了,內核調試步驟如下:

 

說明:下面的步驟中

8349E-mITX-GP>                  表示BDI2000的命令行窗口

   [root@newhost misc-modules]#    表示開發主機

DDD> GDB>                     表示是開發主機上的DDD的調試窗口中

root@mpc8349emitxgp:~#         表示目標系統中

 

1. 獲取恰當的斷點設置位置:

[shyi@newhost pro50_mpc8349_kernel]$ cat System.map |grep start_kernel

c03b05dc T start_kernel  #得到start_kernel的虛擬地址

2.設置斷點,加載內核,啓動DDD的連接

8349E-mITX-GP>reset

8349E-mITX-GP>halt

8349E-mITX-GP>bi 0xc03b05dc (這個值是由System.map中的start_kernel的地址而來的)

8349E-mITX-GP>go

- TARGET: stopped   #提示系統進入斷點了

8349E-mITX-GP>info

    Target CPU        : MPC83xx (e300c1)

    Target state      : debug mode

    Debug entry cause : instruction address breakpoint

    Current PC        : 0xc03b05dc

    Current CR        : 0x44044022

    Current MSR       : 0x00001032

    Current LR        : 0x00003438

8349E-mITX-GP>

# 這時串口可看打到打印信息如:

   Uncompressing Kernel Image ... OK

   Booting using the fdt at 0xc00000

   Loading Device Tree to 007fc000, end 007fefff ... OK

 

圖形系統中啓動DDD

[root@newhost scull]# cd /opt/pro50/montavista/pro/devkit/ppc/83xx/target/root/examples/misc-modules

[root@newhost misc-modules]# ddd --debugger ppc_83xx-gdb –gdb /home/shyi/workspace/pro50_mpc8349_kernel/vmlinux

(gdb)target remote 192.168.7.64:2001 (其中192.168.7.64:2001BDI2000IP和調試端口)

 

8349E-mITX-GP>ci

8349E-mITX-GP>break soft #改變爲軟斷點方式

 

這時候可以在DDD>圖形界面裏面最右邊點擊鼠標右鍵來設置斷點,如圖:

 

 

(注意:系統有些地方不能停住,需要在合適的位置來設置斷點)

(gdb)cont

這時候系統就會停止在斷點設置的地方,接下來就可以進行內核斷點調試了,如下圖:

 

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

 

4.內核模塊的調試

使用LDD3jit.c模塊進行調試的演示,DDD(或者說GDBGDB的初始化腳本放置在~/.gdbinit

其中.gdbinit的內容如下:

 

define lsmod

  printf "Address/t/tModule/n"

  set $m=(struct list_head *)&modules

  set $done=0

  while ( !$done )

  # list_head is 4-bytes into struct module

    set $mp=(struct module *)((char *)$m->next - (char *)4)

    printf "0x%08X/t%s/n", $mp, $mp->name

    if ($mp->list->next == &modules)

      set $done=1

    end

    set $m=$m->next

  end

end

 

define addmodulesymbols

  set $myModule=(struct module*) $arg0

  set $myAddr=$myModule->module_core

  add-symbol-file $arg1 $myAddr

end

document addmodulesymbols

Adds the symbols for a module to the kernel.equires two parameters:

  addmodulesymbols  <0xAddress>  <.ko-file>

end

(說明: 定義了lsmodaddmodulesymbols 2個宏,並且定義了addmodulesymbols的幫助文檔)

 

內核模塊調試前面的步驟和內核調試完全一致,先要在start_kernel的地方設置斷點,然後讓內核能進行調試,接下來:

# DDD<Cont>按鈕繼續內核的運行

 

在內核起來之後à

 

root@mpc8349emitxgp:~# cd /root/examples/misc-modules

root@mpc8349emitxgp:~/examples/scull# insmod ./jit.ko

 

然後在DDD下按<CTRL+C>à

(gdb) lsmod

Address          Module

0xD106FB00      jit

0xD25EE500      ipv6

(gdb) addmodulesymbols 0xd106fb00 ./jit.ko

add symbol table from file "./jit.ko" at

        .text_addr = 0xd106e000

 

   (注意啓動DDD的時候要在此調試模塊的目錄下,否則要指定jit.ko在主機上的絕對路徑位置)

 

(gdb) b jit_currentime

(gdb)cont

 

在目標平臺輸出終端上à

root@mpc8349emitxgp:~/examples/misc-modules# cat /proc/currentime

此時執行停住了,接下來我就可以在DDD中跟蹤驅動的執行了。如下圖:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章