Powerpc構(gòu)架系統(tǒng)內(nèi)核和內(nèi)核模塊調(diào)試
說(shuō)明:
此文檔的目標(biāo)系統(tǒng)為freescale MPC8349E-mITX,對(duì)其他采用powerPC,MIPS,ARM的芯片的系統(tǒng)亦具有參考意義。 此文檔中內(nèi)核調(diào)試為了簡(jiǎn)化,采用目標(biāo)系統(tǒng)中的UBOOT初始化目標(biāo)板,并通過(guò)UBOOT或者BDI2000加載內(nèi)核到目標(biāo)板的RAM中。
1. BDI2000配置:
下面是MPC8349E-mITX的BDI2000配置文件,
; BDI-2000 CONfiguraTIon file for the MPC8349E-mITX
; Tip: If after a reset, the BDI-2000 fails to halt at 0x100,
; you may need to power-down the bOArd for a few seconds.
[INIT]
; we use UBOOT to initialize the board
[TARGET]
CPUTYPE 8349
JTAGCLOCK 1
;STARTUP RESET
STARTUP RUN
BREAKMODE HARD
STEPMODE HWBP
BOOTADDR 0x00000100
;If you‘re getting "Writing to workspace failed" errors during flash operations,
;then try uncommenting this line instead. This moves the FLASH window to
;high memory, leaving low memory available for DDR.
RCW 0xb060a000 0x04040000 ;Set the HRCW to boot the image at 0xFE000000
MMU XLAT ;0xc0000000
PTBASE 0xf0 ;
[HOST]
IP 192.168.7.90
FILE $u-boot.bin
LOAD MANUAL
PROMPT 8349E-mITX-GP>
DUMP itx-dump.bin
[Flash]
CHIPTYPE AM29BX16
CHIPSIZE 0x800000
BUSWIDTH 16
;WORKSPACE 0x1000
FORMAT BIN 0xfe000000
;flash_image.bin is an image file of an entire 8MB flash region.
;Flash this file at 0xfe0000000 to restore all of flash.
;ERASE 0xFE000000 0x10000 127 ; 127 sectors @ 64KB each
;ERASE 0xFE7F0000 0x2000 8 ; 8 sectors @ 8KB each
;FILE $flash_image.bin
;Use these lines if you just want to flash U-Boot
ERASE 0xfe000000 0x10000? 4; Erase 384KB, each sector is 64KB
FILE? mpc8349e/u-boot131-mitx-gp.bin
[REGS]
FILE $reg8349e.def
以上配置文件的【HOST】段的IP要改為主機(jī)IP,關(guān)鍵的字段MMU XLAT 和PTBASE 是POWERPC和MIPS經(jīng)常需要設(shè)置的,關(guān)于PTBASE的具體設(shè)置,超出本文范圍,詳細(xì)情況請(qǐng)參考BDI2000的手冊(cè)
2.內(nèi)核修改和配置
為了能夠調(diào)試內(nèi)核,需要在內(nèi)核中的Makefile中增加如下調(diào)試選項(xiàng):
CFLAGS 增加C代碼調(diào)試選項(xiàng)-g –ggdb
AFLAGS 增加匯編代碼調(diào)試選項(xiàng):-Wa,-L -gdwarf-2
去掉CFLAGS編譯選項(xiàng)中-fomit-frAME-pointer
GCC的-fomit-frame-pointer選項(xiàng)是優(yōu)化函數(shù)?;厮?stack backtrace)的,我們調(diào)試的時(shí)候需要提供函數(shù)回溯能力,所以我們要去掉這個(gè)選項(xiàng),當(dāng)然,有的系統(tǒng)系統(tǒng)不受它的影響,或者說(shuō)它不起作用,為了統(tǒng)一,我們統(tǒng)一去掉它。
相對(duì)個(gè)案來(lái)說(shuō),我是做如下改動(dòng)的:
--- Makefile 2008-07-08 03:07:38.000000000 +0800
+++ Makefile.debug 2008-07-08 03:06:04.000000000 +0800
…
-CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
+ifdef CONFIG_DEBUG_INFO
+
+ CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE) -g -ggdb
-CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs
+ CFLAGS := $(CPPFLAGS) -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs
-fno-strict-aliasing -fno-common
-AFLAGS := -D__ASSEMBLY__
+ AFLAGS := -D__ASSEMBLY__ -Wa,-L -gdwarf-2
+else
+ CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
+ CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs
+ -fno-strict-aliasing -fno-common
+ AFLAGS := -D__ASSEMBLY__
+
+endif
…
@@ -491,27 +500,33 @@
# Defaults vmlinux but it is usually overridden in the arch makefile
all: vmlinux
-ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-CFLAGS += -Os
-else
-CFLAGS += -O2
-endif
include $(srctree)/arch/$(ARCH)/Makefile
-ifdef CONFIG_FRAME_POINTER
-CFLAGS += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
-else
-CFLAGS += -fomit-frame-pointer
-endif
ifdef CONFIG_UNWIND_INFO
CFLAGS += -fasynchronous-unwind-tables
endif
-ifdef CONFIG_DEBUG_INFO
-CFLAGS += -g
-endif
+#ifdef CONFIG_DEBUG_INFO
+CFLAGS += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
+CFLAGS += -g -ggdb
+CFLAGS += -O
+#else
+
+# ifdef CONFIG_FRAME_POINTER
+ CFLAGS += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
+# else
+ CFLAGS += -fomit-frame-pointer
+# endif
+
+# ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
+ CFLAGS += -Os
+# else
+ CFLAGS += -O2
+# endif
+
+#endif
通過(guò)以上修改后,系統(tǒng)的的調(diào)試信息簡(jiǎn)單的通過(guò)CONFIG_DEBUG_INFO宏來(lái)控制了,那么CONFIG_DEBUG_INFO宏又是從哪里來(lái)的呢?它其實(shí)是從內(nèi)核的配置文件.config里面來(lái)的。
一般內(nèi)核通過(guò)make menuconfig做配置的時(shí)候,都有
Kernel hacking --->
[*] Kernel debugging
[*] Compile the kernel with debug info
[*] Force gcc to inline functions marked ‘inline‘ (2.6比較新的內(nèi)核有這一項(xiàng))[!--empirenews.page--]
[*] Include BDI-2000 user context switcher (有的系統(tǒng)直接提供了這個(gè)選項(xiàng),它和BDI2000的PTBASE設(shè)置配合)
通過(guò)保存后,以上選項(xiàng)會(huì)生成如下配置選項(xiàng):
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_INFO=y
CONFIG_FORCED_INLINING=y
CONFIG_BDI_SWITCH=y
值得關(guān)注的是PowerPC內(nèi)核中CONFIG_BDI_SWITCH,它到底在內(nèi)核中怎樣起作用的?
我們看arch/powerpc/kernel/head_32.S的關(guān)鍵代碼:
…
/* 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真正時(shí)能之前先增加了BDI2000幫助信息。在arch/powerpc/kernel/head_32.S的最后通過(guò)abatron_pteptrs保留了8個(gè)自己的空間給BDI2000用于保存2個(gè)頁(yè)表指針,如下:
/* Room for two PTE pointers, usually the kernel and current user pointers
* to their respective root page table.
*/
abatron_pteptrs:
.space 8
3. 內(nèi)核調(diào)試
通過(guò)以上的準(zhǔn)備工作,就可以進(jìn)行內(nèi)核和模塊的調(diào)試了,內(nèi)核調(diào)試步驟如下:
說(shuō)明:下面的步驟中
8349E-mITX-GP> 表示BDI2000的命令行窗口
[root@newhost misc-modules]# 表示開(kāi)發(fā)主機(jī)
DDD> 或GDB> 表示是開(kāi)發(fā)主機(jī)上的DDD的調(diào)試窗口中
root@mpc8349emitxgp:~# 表示目標(biāo)系統(tǒng)中
1. 獲取恰當(dāng)?shù)臄帱c(diǎn)設(shè)置位置:
[shyi@newhost pro50_mpc8349_kernel]$ cat System.map |grep start_kernel
c03b05dc T start_kernel #得到start_kernel的虛擬地址
2.設(shè)置斷點(diǎn),加載內(nèi)核,啟動(dòng)DDD的連接
8349E-mITX-GP>reset
8349E-mITX-GP>halt
8349E-mITX-GP>bi 0xc03b05dc (這個(gè)值是由System.map中的start_kernel的地址而來(lái)的)
8349E-mITX-GP>go
- TARGET: stopped #提示系統(tǒng)進(jìn)入斷點(diǎn)了
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>
# 這時(shí)串口可看打到打印信息如:
Uncompressing Kernel Image ... OK
Booting using the fdt at 0xc00000
Loading Device Tree to 007fc000, end 007fefff ... OK
圖形系統(tǒng)中啟動(dòng)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:2001為BDI2000的IP和調(diào)試端口)
8349E-mITX-GP>ci
8349E-mITX-GP>break soft #改變?yōu)檐洈帱c(diǎn)方式
這時(shí)候可以在DDD>圖形界面里面最右邊點(diǎn)擊鼠標(biāo)右鍵來(lái)設(shè)置斷點(diǎn),如圖:
(注意:系統(tǒng)有些地方不能停住,需要在合適的位置來(lái)設(shè)置斷點(diǎn))
(gdb)cont
這時(shí)候系統(tǒng)就會(huì)停止在斷點(diǎn)設(shè)置的地方,接下來(lái)就可以進(jìn)行內(nèi)核斷點(diǎn)調(diào)試了,如下圖:
4.內(nèi)核模塊的調(diào)試
使用LDD3的jit.c模塊進(jìn)行調(diào)試的演示,DDD(或者說(shuō)GDB)GDB的初始化腳本放置在~/.gdbinit:
其中.gdbinit的內(nèi)容如下:
define lsmod
printf "AddressttModulen"
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%08Xt%sn", $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
(說(shuō)明: 定義了lsmod和addmodulesymbols 2個(gè)宏,并且定義了addmodulesymbols的幫助文檔)
內(nèi)核模塊調(diào)試前面的步驟和內(nèi)核調(diào)試完全一致,先要在start_kernel的地方設(shè)置斷點(diǎn),然后讓內(nèi)核能進(jìn)行調(diào)試,接下來(lái):
# 按DDD的
在內(nèi)核起來(lái)之后→
root@mpc8349emitxgp:~# cd /root/examples/misc-modules[!--empirenews.page--]
root@mpc8349emitxgp:~/examples/scull# insmod ./jit.ko
然后在DDD下按→
(gdb) lsmod
Address Module
0xD106FB00 jit
0xD25EE500 ipv6
(gdb) addmodulesymbols 0xd106fb00 ./jit.ko
add symbol table from file "./jit.ko" at
.text_addr = 0xd106e000
(注意啟動(dòng)DDD的時(shí)候要在此調(diào)試模塊的目錄下,否則要指定jit.ko在主機(jī)上的絕對(duì)路徑位置)
(gdb) b jit_currentime
(gdb)cont
在目標(biāo)平臺(tái)輸出終端上→
root@mpc8349emitxgp:~/examples/misc-modules# cat /proc/currentime
此時(shí)執(zhí)行停住了,接下來(lái)我就可以在DDD中跟蹤驅(qū)動(dòng)的執(zhí)行了。如下圖: