1. 程式人生 > >移植和使用核心函式跟蹤系統KFT

移植和使用核心函式跟蹤系統KFT

移植和使用核心函式跟蹤系統KFT <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

作者:劉旭暉 Raymond轉載請註明出處

以前在2.4核心中使用過KFI來跟蹤核心的函式呼叫,分析效能和幫助理解原始碼,感覺在某些情況下,還是很好用的,最近在新的專案中,需要在短時間內閱讀,維護和修改大量的驅動程式碼。所以又想到了它,因為當前使用的核心沒有整合KFI的後續專案KFT的程式碼,所以做了一些移植和使用的指令碼程式設計工作,記錄在這裡。

對核心函式跟蹤機制不瞭解的可以先看那篇文章,這裡對原理不再做分析。

本人的能力和時間有限,可能下文中有些理解、分析不一定準確,歡迎聯絡指正。

1相關說明

1.1網站資源

KFT<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />2.6.21核心的

1.2工作環境

由於是跟蹤核心,所以KFTkernel的關聯性應該還是比較密切的,KFT的主頁上有2.6.8 2.6.112.6.12 及我所使用的2.6.21等幾個版本的patch

至於我的環境:

Ø硬體平臺:基於ARM的嵌入式板子

Ø軟體環境:Linux 2.6.21,自制檔案系統

2移植

理論上,我的核心版本和patch所針對的版本是精確匹配的,所以本來希望patch打上以後就能用。很可惜,打完patch以後,核心配置選上KFT以後,核心build不通過:

kernel/built-in.o: In function `__cyg_profile_func_exit':

utsname_sysctl.c:(.text+0x2a68c): undefined reference to `cmpxchg'

kernel/built-in.o: In function `__cyg_profile_func_enter':

utsname_sysctl.c:(.text+0x2ad74): undefined reference to `cmpxchg'

make: *** [.tmp_vmlinux1] Error 1

仔細看了一下,cmpxchg的目的應該是做一次原子性的比較和交換的動作,ARM本身不支援這樣的指令。所以,在我的核心中,使用軟體關中斷的方式,實現了一個類似的函式,仿造那部分程式碼在kft.c中添加了一個cmpxchg函式如下:

static inline int __noinstrument cmpxchg(int *v, int old, int new)

{

int ret;

unsigned long flags;

raw_local_irq_save(flags);

ret = *v;

if (likely(ret == old))

*v = new;

raw_local_irq_restore(flags);

return ret;

}

然後,kernel可以Build通過了,只是,不幸的是,下載後的kernel無法啟動了,Uncompressing Linux............................................................................................... done, booting the kernel. 到這一步就停止了,

大致猜想,原因是某部分的核心程式碼不能使用gcc-finstrument-functions引數來編譯,這一點可以在KFTpatch中的很多程式碼上可以看到,使用了__noinstrument 禁止跟蹤,這些修改,有些是為了防止KFT本身的函式迴圈呼叫,有些是因為某些函式必須禁止跟蹤,還有些是未知的原因,可能導致核心崩潰。

沒有合適的硬體偵錯程式方便跟蹤kernel啟動的早期階段(還沒有列印輸出),暫時沒有精力去跟蹤到底那部分出了問題,我只能假設基於ARM平臺,在我使用的核心程式碼中,還有一些部分必須禁止跟蹤,而KFTpatch中沒有處理這一部分。

所以,暫時放棄完美的解決這一問題的企圖,曲線救國吧,修改總的Makefile 把編譯選項-finstrument-functions 去掉。這樣可以使得KFT核心模組本身被編譯,但是,所有的Kernel程式碼不呼叫相關函式,毫無疑問這樣是可以正常把kernel跑起來的。

然後,修改底層驅動的Makefile,僅對部分模組使用-finstrument-functions引數進行編譯。這樣同樣可以實現對這些模組涉及到的函式進行跟蹤的目的。基本能滿足我的要求,缺點是,由於不是所有函式都跟蹤,可能出現跟蹤路徑不完整。(在發生程序切換的場合,似乎有時候還會導致函式呼叫關係的錯誤關聯,這和KFT的跟蹤機制有關,不能怪它,誰叫我沒能完整的跟蹤所有函式,這個問題怎麼解決有點頭大,好在這種錯誤情況一眼就能看出來,大不了重跟蹤一次)

3使用

標準的基本使用方法,可以參考前面列的文章,除此之外,我所面臨的問題是需要能夠支援對以模組的形式插入核心的驅動的跟蹤。

這裡涉及到幾個問題:

3.1如何triggerstop

因為模組在未插入核心之前,沒有辦法得到所需的函式地址,(Buildin的函式是通過 addr2sym 查詢System.map來轉化得到),所以我所能想到的辦法不外乎:

如果確實需要設定由哪個函式進行觸發,那麼插入一次模組,查詢模組的符號表(下一節描述),手工將trigger函式改為對應的地址,重啟系統,以完全相同的步驟插入模組,希望模組載入進來以後,保持函式地址和上次一致。

如果不關心由哪個函式觸發(例如我想了解一下模組插入以後,相關的驅動初始化流程),那麼可以在插入模組前,載入一個基於timetrigger,(只是為了存在一個trigger,沒有trigger KFT沒法啟動)然後,用echo “start” > /proc/kft 進行強制觸發。我的trigger

new

begin

trigger start time 5000

end

Stop也類似了,手工得到函式地址,或者,強制停止。

3.2如何獲得log分析所需的地址和符號表對映

符號對映表通常由System.map得到,我的使用場合下,需要動態的得到模組插入以後總的符號表。

為此,我通過cat /proc/kallsyms > /tmp/kallsyms.bin 來得到執行時的完整符號表。

這個途徑得到的符號表包括所有已經插入的模組的符號,但是,和System.map比較存在一些問題:

Ø符號表沒有完整按照地址排序

Ø符號表有額外的帶$特殊字元的符號存在

Ø模組部分的符號表有4列輸出,比System.map多了一列模組名的顯示

這幾個區別會導致後面的地址轉換成符號的查詢演算法出現問題,不能正常工作,所以,寫了一個簡單的指令碼來處理得到的符號表,使其滿足所需的格式,指令碼如下:

#! /bin/sh

name=$1

nameout=$name".map"

awk '{print $1,$2,$3}' $name| sed /"$"[a-z]/d | sort > $nameout

基本上就是3步:只輸出前3列,去除$a等符號,排序。

3.3處理__INIT函式

__init修飾符的函式,在system.map/proc/kallsyms中都沒有生成符號表,如果要以相關的函式作為觸發,我所能想到的只能是寫一個dummy函式來觸發了。例如下面這個函式:

static int __init u2d_init(void)

{

return platform_driver_register(&u2d_driver);

}

修改成下面的程式碼:

void dummy_u2d_init(void)

{

printk("just for kft trigger");

return;

}

static int __init u2d_init(void)

{

dummy_u2d_init();

return platform_driver_register(&u2d_driver);

}

這樣,以dummy_u2d_init作為觸發函式,即可。

不知道是否有更好的解決辦法。

3.4繪製函式呼叫圖

得到log,按照kft的標準用法,使用kd等工具已經可以對資料進行分析,不過我的目的之一依然是希望得到函式呼叫圖,所以參照以前的做法,修改了轉換指令碼以及mtjones 所寫的graphviz所需Dot檔案的生成程式。

上傳到了google doc

3.4.1使用:

使用上述指令碼,程式,完成畫圖所需的工作的大致流程如下:

../sym2map.sh kallsyms.bin

../mykftres.py kft.log kallsyms.bin.map > kft.call

../mypvtrace/pvtrace kft.call

dot -Tjpg graph.dot -o kft.jpg

../addr2sym < kft.log -m kallsyms.bin.map > kft.lst

../kd -c -r kft.lst > kft.ctree

下圖是實際跟蹤usb gadge filestorage的模組的初始化過程得到的函式呼叫圖中的一小部分:

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

example image

4遺留問題

Ø__init 巨集修飾的函式沒法從/proc/kallsym中獲得,這些函式就沒法查詢定位了

Ø部分 static函式,如果只被一個函式呼叫,那麼該static函式可能會被優化成行內函數,無法跟蹤。

Ø完全使能-finstrument-functions編譯選項導致核心無法啟動