Linux內(nèi)核調(diào)試篇——獲取內(nèi)核函數(shù)地址的四種方法(一文解決)

在內(nèi)核調(diào)試中,經(jīng)常需要知道某個函數(shù)的地址,或者根據(jù)函數(shù)地址找到對應(yīng)的函數(shù),從而進(jìn)行更深一步的debug。
下面介紹四種獲取內(nèi)核函數(shù)地址的方法:
1、System.map
在編譯Linux內(nèi)核時,會產(chǎn)生一個內(nèi)核映像文件System.map
,也叫內(nèi)核符號表。
內(nèi)核符號表是一個映射,它將內(nèi)核代碼段中的地址映射到對應(yīng)的函數(shù)名或全局變量名。
在System.map
文件中,每一行都包含一個內(nèi)核符號,每個符號包含三部分:
地址:符號在內(nèi)核內(nèi)存中的地址。
類型:符號的類型。例如,"T"表示該符號是一個在代碼段中的函數(shù)。
名稱:符號的名字,可以是函數(shù)名或者變量名。
例如,我們要查找名為“do_fork
”的函數(shù)的地址,可以使用以下命令:
然后會得到類似于這樣的輸出:
這代表,c0105020
就是函數(shù)do_fork
的地址,T
代表該符號是個函數(shù)。
或者,直接打開System.map
搜索對應(yīng)函數(shù)名或者地址。System.map
內(nèi)容類似如下:
A、T、t等都代表不同的類型,具體類型的定義可參考:

【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【749907784】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)? ? ?


零聲白金VIP體驗卡(含基礎(chǔ)架構(gòu)/高性能存儲/golang/QT/音視頻/Linux內(nèi)核)課程:?

2、vmlinux
vmlinux
也是Linux
編譯出來的內(nèi)核映像文件,可以通過nm
、objdump
和readelf
等工具來查看它的符號表,從而獲取函數(shù)地址。
2.1 nm讀取vmlinux
nm
命令是用于查看二進(jìn)制文件(如可執(zhí)行文件、目標(biāo)文件、庫)的符號表的工具,所以可以用nm
命令來讀取vmlinux
里的符號表。
nm
查找vmlinux
中函數(shù)名為do_fork
的地址:
nm
查找vmlinux
中地址為c0105020
的符號:
nm
命令的輸出,與System.map
類似,會的得到類似于以下的輸出:
2.2 objdump反匯編vmlinux
objdump
工具用于反匯編,可以將vmlinux
反匯編出來,得到的反匯編文件就會包含函數(shù)名和對應(yīng)的地址,可以直接查看文本內(nèi)容。
使用objdump查看vmlinux函數(shù)地址:
這會返回與指定函數(shù)名匹配的符號的地址、類型和名稱。objdump
的-d
選項表示反匯編代碼。
也可以將vmlinux的內(nèi)容全部反匯編出來,重定向到一個文件,然后直接查看文本內(nèi)容:
上述命令會將vmlinux
所有內(nèi)容反匯編,并將結(jié)果輸出到vmlinux_dump.txt
文件中,-D
表示反匯編所有代碼段。
2.3 readelf讀取vmlinux
使用readelf也可以讀取vmlinux的符號表,命令如下:
由于vmlinux比較大,如果要查找某個函數(shù)的地址,需要使用grep進(jìn)行過濾。
例如,找到do_fork
函數(shù)的地址,你可以使用以下命令:
然后,你就會看到類似這樣的輸出:
輸出內(nèi)容表示,do_fork
函數(shù)的地址是c10601e0
。
3、/proc/kallsyms
vmlinux
是編譯時生成的,假設(shè)你沒有vmlinux
這個文件,只有正在運行的Linux
系統(tǒng),此時也可以通過/proc/kallsyms
獲取函數(shù)地址。
/proc/kallsyms
是一個由運行中的內(nèi)核動態(tài)生成的虛擬文件,它反映了當(dāng)前運行的內(nèi)核的狀態(tài)。
通常這個節(jié)點是不會打開的,因為會增加內(nèi)核大小,要使用這個節(jié)點,需要打開內(nèi)核選項:
如果想獲取do_fork
函數(shù)的地址,可以使用以下命令:
然后會返回一個包含do_fork
函數(shù)地址的行,如:
輸出內(nèi)容表示do_fork
函數(shù)的地址是ffffffff810b57b0
。
4、內(nèi)核接口
也可以在代碼中獲取內(nèi)核符號表,同樣需要打開內(nèi)核選項CONFIG_KALLSYMS=y
。
kallsyms_lookup_name
已知函數(shù)名,獲取地址:
該函數(shù)會返回對應(yīng)函數(shù)名的地址。
sprint_symbol
已知地址,返回對應(yīng)符號:
buffer:符號名緩存區(qū),保存結(jié)果。
address:符號地址。
原文作者:嵌入式Linux充電站
